{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2023年度計算機演習A・B\n",
    "\n",
    "# 第11回：行列と幾何変換2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 平行移動とアフィン変換\n",
    "\n",
    "前回の授業では、与えられた点や図形に対して幾何変換を行うことを考え、行列を用いて表現される線形変換（特に、拡大・縮小変換、回転変換、対称変換、せん断変換）について扱いました。\n",
    "\n",
    "今回の授業では、平行移動とアフィン変換について扱います。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.1. 平行移動\n",
    "\n",
    "変換前の点を $(x,y)$、変換後の点を $(x',y')$ とするとき、$x$ 軸方向に $p$、$y$ 軸方向に $q$ だけ**平行移動**する変換は、\n",
    "\n",
    "$$\n",
    "\\begin{pmatrix}\n",
    "x'\\\\\n",
    "y'\n",
    "\\end{pmatrix}\n",
    "=\n",
    "\\begin{pmatrix}\n",
    "x\\\\\n",
    "y\n",
    "\\end{pmatrix}\n",
    "+\n",
    "\\begin{pmatrix}\n",
    "p\\\\\n",
    "q\n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "と表されます。\n",
    "\n",
    "例として、前回の1.1の三角形に対して $x$ 軸方向に $2$、$y$ 軸方向に $1$ だけ平行移動する変換を行うと、次のようになります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "triangle_nodes = np.array([[0,0],[1,0],[1,1],[0,0]]).T  #変換前の点からなる行列\n",
    "\n",
    "plt.gca().set_aspect(\"equal\")\n",
    "\n",
    "plt.plot(triangle_nodes[0,:],triangle_nodes[1,:],\"r-\")  #変換前の三角形の描画（赤色）\n",
    "\n",
    "b = np.array([[2,1]]).T  #平行移動ベクトル\n",
    "new_triangle_nodes = triangle_nodes+b  #変換後の点からなる行列（各列にbを足す）\n",
    "\n",
    "plt.plot(new_triangle_nodes[0,:],new_triangle_nodes[1,:],\"b-\")  #変換後の三角形の描画（青色）\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2. アフィン変換\n",
    "\n",
    "**アフィン変換（affine transformation）**は、線形変換と平行移動を組み合わせた変換であり、\n",
    "\n",
    "$$\n",
    "\\begin{pmatrix}\n",
    "x'\\\\\n",
    "y'\n",
    "\\end{pmatrix}\n",
    "=A\n",
    "\\begin{pmatrix}\n",
    "x\\\\\n",
    "y\n",
    "\\end{pmatrix}\n",
    "+\n",
    "\\begin{pmatrix}\n",
    "p\\\\\n",
    "q\n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "の形で表されます。ここで、$A$ は $2\\times 2$ の行列です。\n",
    "\n",
    "$p=q=0$ の場合には線形変換、$A$ が単位行列の場合には平行移動になるため、アフィン変換は線形変換および平行移動を一般化した概念であることが分かります。\n",
    "\n",
    "例として、前回の1.1の三角形に対して $x$ 軸方向に $2$ 倍、$y$ 軸方向に $1.5$ 倍してから $x$ 軸方向に $2$、$y$ 軸方向に $1$ だけ平行移動する変換を行うと、次のようになります。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "triangle_nodes = np.array([[0,0],[1,0],[1,1],[0,0]]).T  #変換前の点からなる行列\n",
    "\n",
    "plt.gca().set_aspect(\"equal\")\n",
    "\n",
    "plt.plot(triangle_nodes[0,:],triangle_nodes[1,:],\"r-\")  #変換前の三角形の描画（赤色）\n",
    "\n",
    "A = np.array([[2,0],[0,1.5]])  #線形変換行列\n",
    "b = np.array([[2,1]]).T  #平行移動ベクトル\n",
    "new_triangle_nodes = A@triangle_nodes+b  #変換後の点からなる行列\n",
    "\n",
    "plt.plot(new_triangle_nodes[0,:],new_triangle_nodes[1,:],\"b-\")  #変換後の三角形の描画（青色）\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 様々な家の描画\n",
    "\n",
    "ここでは、前回描画した家の図に対してアフィン変換を行うことを考えます。\n",
    "\n",
    "まず、家に対して塗りつぶしや色の変更を適宜行った上で、その描画を行う関数を定義します。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def house():\n",
    "    roof_nodes = np.array([[0,3],[-3,2],[3,2],[0,3]]).T\n",
    "    wall_nodes = np.array([[-2,2],[-2,0],[2,0],[2,2],[-2,2]]).T\n",
    "\n",
    "    plt.gca().set_aspect(\"equal\")\n",
    "\n",
    "    plt.plot(roof_nodes[0,:],roof_nodes[1,:],color=\"purple\")\n",
    "    plt.fill(roof_nodes[0,:],roof_nodes[1,:],color=\"purple\",alpha=0.5)  #不透明度0.5で塗りつぶす\n",
    "    plt.plot(wall_nodes[0,:],wall_nodes[1,:],color=\"purple\")\n",
    "\n",
    "house()  #定義した関数を呼び出す\n",
    "plt.show()  #後で複数の家を一つの図に描画するため、関数の中には入れない"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`matplotlib`における色の指定方法は、色の頭文字、カラーネーム、RGB形式、16進数カラーコードなど複数用意されています。詳しくは、[参考リンク](https://www.yutaka-note.com/entry/matplotlib_color)をご覧ください。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 演習1\n",
    "\n",
    "自分なりの家の図を描画する関数`house()`を定義し、その関数を呼び出してください。前回の演習1の内容に加えて、適宜塗りつぶしや色の変更を行うこと。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#演習1のコード\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def house():\n",
    "    #ここに、コードを書く\n",
    "    #plt.show()は不要\n",
    "\n",
    "house()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "次に、家に対して任意のアフィン変換を行った結果を描画する関数を定義します。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 演習2\n",
    "\n",
    "演習1の家に対して行列 $A$ と ベクトル $b$ によるアフィン変換を行った結果を描画する関数`house_transform(A,b)`を定義し、変換前の家と適当なアフィン変換を行った家を一つの図に描画してください。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#演習2のコード\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "def house_transform(A,b):\n",
    "    #ここに、コードを書く\n",
    "    #plt.show()は不要\n",
    "\n",
    "house()  #変換前の家の描画\n",
    "\n",
    "#ここで、Aとbを適当に定める\n",
    "\n",
    "house_transform(A,b)  #変換後の家の描画\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 演習3（オプション）\n",
    "\n",
    "演習1の関数`house()`と演習2の関数`house_transform(A,b)`を利用して、\n",
    "\n",
    "- 変換前の家\n",
    "\n",
    "- 反時計回りに $15$ 度だけ回転した後、$x$ 軸方向に $2$、$y$ 軸方向に $3$ だけ平行移動した家\n",
    "\n",
    "- $x$ 軸方向に $2$、$y$ 軸方向に $3$ だけ平行移動した後、反時計回りに $15$ 度だけ回転した家\n",
    "\n",
    "を一つの図に描画してください。\n",
    "\n",
    "さらに、線形変換と平行移動の順番を変えることの意味について考察してください。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#演習3のコード"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "（Markdownとして考察を書く）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第11回レポート課題\n",
    "\n",
    "演習1～演習3に取り組んでください。"
   ]
  }
 ],
 "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.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
