直角坐标系坐标换算

同一个点坐标(x,y),在canvas坐标系变换后(点位置不变),计算此点在新坐标系的(x,y)值

只研究使用 translate() rotate() scale()三个方法变换后的坐标系

平移变换

p1(80,50) 在默认坐标系中的位置. 坐标轴不是数学的那种,是左上角为顶点的,右和下为正方向

调用translate(150,70)后,p1n点新坐标值位置. 原来p1点的坐标位置.p1与p1n的关系如下

p1.x = p1n.x - 150 , p1.y = p1n.y - 70 这是简单的坐标系原点变化.

p.x = p0.x - o.x ,p.y = p0.y - o.y (o是新原点坐标)

旋转变换

调用rotate()30度后,p1n与p1.虚线是旋转后的X轴

这个比平移变换复杂些,看下图理解转换关系公式

y = y0 * cos(θ) - x0 * sin(θ) ; x = x0 * cos(θ) + y0 * sin(θ)

通过计算p点,在原坐标系和新坐标系中的x,y值,推算出x1,y1和x,y的关系.也就是上面的公式.

推演过程

1. 坐标系由C0(灰色虚线箭头)旋转θ度,变为C(棕色虚线箭头)

2. p点(红色圆点)坐标,在C0坐标系中的(x0,y0)值(蓝色虚线),在C坐标系中的(x,y)值(绿色虚线)

3. 由图很直观看出, x = 桔色线段[x0 * cos(θ)] + 红色线段[y0 * sin(θ)] , y = 绿色线段[y0 * cos(θ)] - 天蓝色线段[ x0 * sin(θ)]

4. 关键辅助线是两个直角三角形,1是红色线段和绿色线段和蓝色虚线(y0)组成,2是桔色线段和天蓝色线段和蓝色虚线(x0)的平行线组成

5. 而这样做辅助线的原理是,要借用C0坐标系已知的(x0,y0)值,还有已知的θ角度.然后便于运用三角函数计算.

缩放变换

调用scale(2,2)后,p1n与p1

缩放前后坐标关系是 x = x0 / zoom.x , y = y0 / zoom.y , 这个比较简单,和平移变换类似

组合变换

实际任务中,会组合这三种变换.例如,平移后旋转再放大,或者旋转后放大再平移.

这个也不复杂,按照公式就可以求出p点在变换后坐标系的坐标.只是有一点要注意,"变换顺序"

下图p1n点的坐标系经过1.平移, 2旋转, 3缩放.那么,还原这些变换后的p1点是怎么求出的

1.先平移,得到 pox = p1.x - o.x , poy = p1.x - o.y

2.再旋转,prx = pox * cos(θ) + poy * sin(θ) , pry = poy * cos(θ) - pox * sin(θ)

3.再缩放,px = prx / zoom.x , py = pry / zoom. y

还是依靠公式,不过重要的再说一次,"变换顺序".按照怎样的顺序做的变换,必须要按照相同的顺序用公式.

前次用公式算出的坐标值,是其后公式的坐标值参数.所以,顺序是不能乱的.

矩阵变换

canvas矩阵变换方法除了这三个,还有transform(),这个可以设定矩阵参数,一次调用实现组合变换

矩阵乘法是不满足交换律的,这也是为什么在求变换后坐标时,不能颠倒顺序的理论依据

同一点位在坐标变换前后的(x,y)值

已知点位p(x,y),求该点位在坐标变换后的坐标系中p1(x,y)值.下面分两种情况求点坐标值.

1. 点p(50,30),是默认坐标系的点,在平移变换(20,20),旋转变换(30度),缩放变换(1.5,1.5)倍后,新坐标系中的p1(x,y)值

2. 点q(50,30),是变换后坐标系的点(变换参数同上),在默认坐标系中的q1(x,y)值

公式

上面两种变换情况的区别在于坐标系参照,假设原坐标系是默认坐标系,记(Z).变换后坐标系是基于Z变换的,记(Z1).那么

Z~Z1变换: p(x,y),Z坐标系,在坐标系变换为Z1后,对应位置p1(x,y)的计算公式:

// 平移变换
p1.x = p.x - Z1.x , p1.y = p.y - Z1.y 

// 旋转变换
p1.y = p.y * cos( θ ) - p.x * sin( θ ) 
p1.x = p.x * cos( θ ) + p.y * sin( θ )

// 缩放变换
p1.x = p.x / zoom.x 
p1.y = p.y / zoom.y 

Z1~Z变换: p1(x,y),Z1坐标系,在坐标系变回Z后,对应位置p(x,y)的计算公式:

// 平移变换
p.x = p1.x - ( - Z1.x ) , p.y = p1.y - ( - Z1.x )
或者 p.x = p1.x + Z1.x  , p.y = p1.y + Z1.x

// 旋转变换
p.y = p1.y * cos( - θ ) - p1.x * sin( - θ ) 
p.x = p1.x * cos( - θ ) + p1.y * sin( - θ )

// 缩放变换
p.x = p1.x / ( 1 / zoom.x )
p.y = p1.y / ( 1 / zoom.y )
或者
p.x = p1.x * zoom.x
p.y = p1.y * zoom.y

可见,这两种变换在使用公式时,只需要传入参数的"相反"值.

如:平移变换传(-o.x , -o.y),旋转变换传(-angle),缩放变换传(1/zoom.x , 1/zoom.y)