05
2023
05

器材拖动旋转

## 器材旋转。

鼠标按下,获取器材内部鼠标按下的位置(不动点)。

鼠标移动,旋转器材,使得旋转之后,不动点仍然在鼠标下方。

之前都是记住上一次的旋转角度,计算出旋转了多少度(可以用全局坐标系),然后加上去。这里我们换一种方法。

假设器材不缩放。

假设一个点的坐标是(x,y),旋转角度θ,旋转之后的坐标是(x',y'),有:
$$
\begin{bmatrix}
cos(θ) & -sin(θ) \\\\
sin(θ) & cos(θ)
\end{bmatrix}
\begin{bmatrix}
x\\\\
y
\end{bmatrix}=
\begin{bmatrix}
x^{\prime}\\\\
y^{\prime}
\end{bmatrix}\tag{1}
$$

假设不动点是$x_0、y_0$,不动点对应的器材外部的坐标为$x_1、y_1$,器材旋转角度为$θ_1$,有:
$$
\begin{bmatrix}
c_1 & -s_1\\\\
s_1 & c_1
\end{bmatrix}
\begin{bmatrix}
x_0\\\\
y_0
\end{bmatrix}=
\begin{bmatrix}
x_1\\\\
y_1
\end{bmatrix}\tag{1}
$$
其中$c_1=cos(θ_1),s_1=sin(θ_1)$。

$x_0、y_0$是已知的,就是鼠标按下时,鼠标位置对应的器材内部点的坐标,$θ_0$是已知的,就是器材当前的旋转角度,$x_1、y_1$也是已知的,就是鼠标按下的位置对应的器材外部的坐标。

转转之后,假设器材旋转角度为$θ_2$,有:
$$
\begin{bmatrix}
c_2 & -s_2\\\\
s_2 & c_2
\end{bmatrix}
\begin{bmatrix}
x_0\\\\
y_0
\end{bmatrix}=
\begin{bmatrix}
x_2\\\\
y_2
\end{bmatrix}\tag{2}
$$
其中$c_2=cos(θ_2),s_2=sin(θ_2)$。
我们的目标是求出$θ_2$。
$x_0、y_0$是已知的,$x_1、y_1$也是已知的,同上。

联立(1)、(2),得到方程组:
$$
\begin{cases}
x_1=c_1x_0 - s_1y_0 \\\\
y_1=s_1x_0 + c_1y_0 \\\\
x_2=c_2x_0 - s_2y_0 \\\\
y_2=s_2x_0 + c_2y_0 \\\\
\end{cases} \tag{3}
$$
可以求出:
$$
\begin{cases}
c_2=\displaystyle{\frac{x_0x_2+y_0y_2}{x_0x_0+y_0y_0}} \\\\
s_2=\displaystyle{\frac{x_0y_2-x_2y_0}{x_0x_0+y_0y_0}} \\\\
\end{cases} \tag{4}
$$
可以得到:
$$
t_2=\frac{s_2}{c_2}=\displaystyle{\frac{x_0y_2-x_2y_0}{x_0x_2+y_0y_2}}
$$
其中$t_2=tan(θ_2)$。

求得了$t_2$,也就得到了$θ_2$。

以下是ActionScript代码,实现,点击拖动TouchRotItem,旋转TouchRotItem的parent。

```ActionScript
package 
{
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	/**
	 * ...
	 * @author hanyeah
	 */
	public class TouchRotItem extends MovieClip
	{

		protected var localP: Point;
		public function TouchRotItem() 
		{
			addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
		}

		private function mouseDownHandler(e:MouseEvent):void 
		{
			e.stopPropagation();
			localP = parent.globalToLocal(new Point(e.stageX, e.stageY));
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
		}

		private function mouseMoveHandler(e:MouseEvent):void 
		{
			var x0: Number = localP.x;
			var y0: Number = localP.y;
			var p2: Point = parent.parent.globalToLocal(new Point(e.stageX, e.stageY));
      // 相对于parent原点的坐标
			p2.x -= parent.x;
			p2.y -= parent.y;
			var x2: Number = p2.x;
			var y2: Number = p2.y;
			var s2: Number = x0 * y2 - x2 * y0;
			var c2: Number = x0 * x2 + y0 * y2;
			var t2: Number = s2 / c2;
			var dir: Number = c2 > 0 ? 1: -1;
			var rot = Math.atan2(t2 * dir, dir) * 180 / Math.PI;

			parent.rotation = rot;
		}

		private function mouseUpHandler(e:MouseEvent):void 
		{
			stage.removeEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
		}

	}

}
```


« 上一篇下一篇 »

相关文章:

器材拖动旋转2  (2023-5-5 17:38:19)

沿任意轨迹拖动  (2019-12-11 9:40:45)

安卓原生控件做时钟  (2017-3-3 16:48:11)

按下拖动双击编辑  (2016-4-21 9:31:28)

tree组件拖动改变节点顺序  (2016-4-21 8:52:5)

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。