{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 行列と幾何変換 III\n",
    "\n",
    "本資料では、同次座標系と合成変換を紹介します。余裕がある方は各自で資料を読んでコードを試してみてください。\n",
    "質問がある場合、担当教員に聞いてください。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 復習\n",
    "\n",
    "「家」の描画は繰り返し使用されますので、関数としてまとめて定義しましょう。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def myhome():\n",
    "    import matplotlib.pyplot as plt\n",
    "    import numpy as np\n",
    "    p_list = np.array([[-3,2],[-2,2],[-2,0],[2,0],[2,2],[3,2],[0,3],[-3,2]]).T\n",
    "\n",
    "    plt.plot(p_list[0,:], p_list[1,:], '-r')\n",
    "    plt.gca().set_aspect('equal')\n",
    "    plt.grid()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "myhomeを使って、家を描いてみます。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "myhome()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 同次座標系"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "平面上の点$(x,y)$を以下のように拡張して、同次座標系で表現することができます。\n",
    "\n",
    "$$\n",
    "\\left(\\begin{array}{c}x\\\\y\\end{array}\\right) \\Rightarrow \n",
    "\\left(\\begin{array}{c}x\\\\y\\\\1 \\end{array}\\right)\n",
    "$$\n",
    "\n",
    "同次座標系から普通の座標系への変換（$c\\not =0$ のとき）：\n",
    "\n",
    "$$(x,y,c) \\Rightarrow  \\left(\\frac{x}{c},\\frac{y}{c}\\right)$$\n",
    "\n",
    "\n",
    "同次座標系を使えば、アフィン変換は行列とベクトルの積として書けます。\n",
    "\n",
    "例えば、アフィン変換\n",
    "$$\n",
    "\\left(\\begin{array}{c}x\\\\y\\end{array}\\right) \\Rightarrow \\left(\\begin{array}{c}x'\\\\y'\\end{array}\\right) = \n",
    "\\left(\\begin{array}{cc}a&b\\\\ c& d\\end{array}\\right)\n",
    "\\left(\\begin{array}{c}x\\\\y\\end{array}\\right) + \\left(\\begin{array}{c}x_0 \\\\ y_0 \\end{array}\\right)\n",
    "$$\n",
    "\n",
    "に対して同次座標系を使うと、アフィン変換を一つの行列にまとめることができます。\n",
    "\n",
    "$$\n",
    "\\left(\\begin{array}{c}x\\\\y\\\\1 \\end{array}\\right)\n",
    "\\Rightarrow\n",
    "\\left(\\begin{array}{c}x'\\\\y'\\\\1 \\end{array}\\right)\n",
    "=A\\left(\\begin{array}{c}x\\\\y\\\\1 \\end{array}\\right), \\quad\n",
    "A=\\left(\\begin{array}{ccc}a&b&x_0\\\\ c&d & y_0 \\\\ 0 & 0 & 1 \\end{array}\\right) \n",
    "$$\n",
    "\n",
    "回転変換を表す行列は以下のようになります。\n",
    "$$\n",
    "A = \\left(\\begin{array}{ccc}\\cos \\alpha & -\\sin \\alpha & 0\\\\  \\sin\\alpha & \\cos \\alpha & 0 \\\\0 & 0 & 1 \\end{array}\\right)\n",
    "$$\n",
    "\n",
    "$(x_0,y_0)$による平行移動を表す行列は以下のようになります。\n",
    "\n",
    "$$\n",
    "A = \\left(\\begin{array}{ccc} 1 & 0 & x_0 \\\\  0 & 1 & y_0\\\\ 0 & 0 & 1 \\end{array}\\right)\n",
    "$$\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 例１\n",
    "\n",
    "以下のコードでは「家」を反時計回りに$\\alpha=30$度回転して、ベクトル(5,1)だけ平行移動します。\n",
    "\n",
    "変換行列：\n",
    "$$\n",
    "A = \\left(\\begin{array}{ccc}\\cos \\alpha & -\\sin \\alpha & 5\\\\  \\sin\\alpha & \\cos \\alpha & 1 \\\\0 & 0 & 1 \\end{array}\\right)\n",
    "$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import math\n",
    "\n",
    "def myhome_affine(A):\n",
    "    #同次座標系で表された点列\n",
    "    p_list = np.array([[-3,2,1],[-2,2,1],[-2,0,1],[2,0,1],[2,2,1],[3,2,1],[0,3,1],[-3,2,1]]).T\n",
    "    plt.plot(p_list[0,:], p_list[1,:], '-r')\n",
    "\n",
    "    #変換行列を同次座標系で表された点列に掛ける\n",
    "    new_p_list = A@p_list\n",
    "\n",
    "    plt.plot(new_p_list[0,:]/new_p_list[2,:], new_p_list[1,:]/new_p_list[2,:], '-b')\n",
    "    plt.gca().set_aspect('equal')\n",
    "    plt.grid()\n",
    "    \n",
    "#同次座標系における変換行列\n",
    "alpha=30/180*math.pi;\n",
    "A=[[math.cos(alpha), -math.sin(alpha), 5],  \n",
    "   [math.sin(alpha), math.cos(alpha), 1],\n",
    "   [0, 0, 1]]\n",
    "\n",
    "myhome_affine(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 演習 1\n",
    "\n",
    "レポート課題で作成した「私の家」を、同次座標系の形に直してみてください。ここで、変換行列は$3 \\times 3$の行列であることに注意してください。\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "#演習1\n",
    "def myhome_affine(A):\n",
    "    pass\n",
    "    # Input parameter A\n",
    "    # A: 3*3 matrix"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 合成変換\n",
    "\n",
    "同次座標系を使う場合、合成変換は行列の積の形で書けます。例えば、平面上の点に対する２つの変換を考え、それぞれの変換に対応する行列を$A_1$, $A_2$とします。\n",
    "このとき、２つの変換の合成に対応する行列$A$は次のようになります。\n",
    "\n",
    "- $A_1$の後に$A_2$を作用させる場合、$A=A_2A_1$。\n",
    "- $A_2$の後に$A_1$を作用させる場合、$A=A_1A_2$。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 演習2\n",
    "\n",
    "家を$(2,3)$だけ平行移動する変換$A_1$と反時計回りに$\\alpha = 10$度回転する変換$A_2$を考えます。\n",
    "\n",
    "$$\n",
    "A_1 = \\left(\\begin{array}{ccc} 1 & 0 & 2 \\\\  0 & 1 & 3\\\\ 0 & 0 & 1 \\end{array}\\right),\n",
    "\\quad\n",
    "A_2 = \\left(\\begin{array}{ccc}\\cos \\alpha & -\\sin \\alpha & 0\\\\  \\sin\\alpha & \\cos \\alpha & 0 \\\\0 & 0 & 1 \\end{array}\\right)\\:.\n",
    "$$\n",
    "\n",
    "行列$B_1=A_1A_2$と$B_2=A_2A_1$をそれぞれ家を表す点列に掛けて、変換結果の違いを確認してください。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "#演習2\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
