我在代码下做了仿射变换。
/**
* @description getAffineTransform using SRT
* @param {Number} xScale xScale
* @param {Number} yScale yScale
* @param {Number} radian radian
* @param {Point} position position
* @param {Point} pivot pivot
* @return {CanvasMatrix} CanvasMatrix
* @member CoordinateSystem#getAffineTransform
*/
getAffineTransform(xScale, yScale, radian, position, pivot) {
let a, b, c, d;
let matrix = new CanvasMatrix();
// origin to pivot
if (pivot) {
matrix = matrix.multiply(new CanvasMatrix(1, 0, 0, 1, pivot.x, pivot.y));
}
// Scale
matrix = matrix.multiply(new CanvasMatrix(xScale, 0, 0, yScale, 0, 0));
// Rotate
if (this._opt.orientation === ORIENTATION.CCW) {
a = Math.cos(radian);
b = -Math.sin(radian);
c = Math.sin(radian);
d = Math.cos(radian);
} else {
a = Math.cos(radian);
b = Math.sin(radian);
c = -Math.sin(radian);
d = Math.cos(radian);
}
matrix = matrix.multiply(new CanvasMatrix(a, b, c, d, 0, 0));
// Translate
matrix = matrix.multiply(new CanvasMatrix(1, 0, 0, 1, position.x, position.y));
// pivot to origin'
if (pivot) {
matrix = matrix.multiply(new CanvasMatrix(1, 0, 0, 1, -pivot.x, -pivot.y));
}
return matrix;
}
没有移动枢轴,它工作得很好。 但是,如果我将旧枢轴移动到新枢轴,它就不起作用。 它由新的枢轴重置。 我怎样才能保持原状。
答案 0 :(得分:0)
你所拥有的函数过于复杂,6个矩阵得到一个加上所有乘法对于单个变换来说是很多工作。
2D矩阵最好一次性处理
// radian is negative if CCW
// Pivot and position do not effect the first 4 of the matrix a,b,c,d
// xScale and yScale only effect the x and y axis respectively so can be combine
// with the rotation
// Returns matrix as a 6 item array [a,b,c,d,e,f]
function getAffineTransform(xScale, yScale, radian, position, pivot){
const m = [ // m for matrix
Math.cos(radian) * xScale,
Math.sin(radian) * xScale,
-Math.sin(radian) * yScale,
Math.cos(radian) * yScale,
];
m[4] = pivot.x - position.x * m[0] - position.y * m[2];
m[5] = pivot.y - position.x * m[1] - position.y * m[3];
return m;
}
虽然我不确定你的意思是枢轴(假设它是旋转点)而且位置是偏离它的。
如果相反,那么在返回之前交换最后两行。
我发现理解2D变换最好考虑值a
,b
,c
,d
,e
,{{1定义x轴(a,b)矢量的矢量,定义y轴(c,d)的尺度和方向以及原点坐标(e,f)
因此,变换标识为1,0(x轴)0,1(y轴)和0,0(原点),按2缩放为2,0,0,2,0,0,以旋转90 CW是0,2,-2,0,0,0
f
const ctx = can.getContext("2d");
function getAffineTransform(xScale, yScale, radian, position, pivot){
const m = [ // m for matrix
Math.cos(radian) * xScale,
Math.sin(radian) * xScale,
-Math.sin(radian) * yScale,
Math.cos(radian) * yScale,
];
m[4] = pivot.x - position.x * m[0] - position.y * m[2];
m[5] = pivot.y - position.x * m[1] - position.y * m[3];
return m;
}
const vals = {
XScale : 1,
YScale : 1,
PosX : 0,
PosY : 0,
PivX : 0,
PivY : 0,
Rot : 0,
}
const props = Object.keys(vals);
const mouse = { down : false };
inputs.addEventListener("mousedown",()=>mouse.down = true);
inputs.addEventListener("mouseup",()=>mouse.down = false);
inputs.addEventListener("mousemove",()=>{
if(mouse.down){
updateDom();
}
})
function updateDom(){
props.forEach(key => { window["el"+key].textContent = vals[key] = Number(window["in"+ key].value); })
drawBox()
}
function setupDom(){
props.forEach(key => { window["el"+key].textContent = window["in"+ key].value = vals[key]; })
drawBox()
}
function drawBox(){
if(can.width !== innerWidth || can.height !== innerHeight){
can.width = innerWidth;
can.height = innerHeight;
}
ctx.setTransform(1,0,0,1,0,0);
ctx.clearRect(0,0,innerWidth,innerHeight);
const mat = getAffineTransform(
vals.XScale,
vals.YScale,
vals.Rot,
{x : vals.PosX, y: vals.PosY},
{x : vals.PivX, y: vals.PivY}
);
ctx.setTransform(mat[0],mat[1],mat[2],mat[3],mat[4],mat[5]);
ctx.strokeRect(0,0,100,100);
ctx.strokeRect(vals.PosX-2,vals.PosY-2,4,4);
}
setupDom();
canvas {
position : absolute;
top : 0px;
left : 0px;
z-index : -10;
}