{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2023年度計算機演習A・B\n",
    "\n",
    "# 第10回：行列と幾何変換1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 線分を用いた図形の描画\n",
    "\n",
    "`matplotlib.pyplot`ライブラリの`plot`関数は、複数の点を結んで折れ線グラフを描画するものです。これまでの授業では、数列や関数のグラフを描画するために使用してきました。\n",
    "\n",
    "今回の授業では、`plot`関数を使用することで線分を組み合わせてできるような図形を描画します。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.1. 三角形の描画\n",
    "\n",
    "三つの点 $(0,0),(1,0),(1,1)$ を頂点にもつような三角形を描画してみましょう。\n",
    "\n",
    "このような三角形を描画するには、当然ながら $(0,0)$ と $(1,0)$、$(1,0)$ と $(1,1)$、$(1,1)$ と $(0,0)$ をそれぞれ線分で結ぶ必要があります。そのため、次のようなNumPyの $2\\times 4$ の2次元配列（行列）`triangle_nodes`を用意します。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "triangle_nodes = np.array([[0,0],[1,0],[1,1],[0,0]]).T  #「.T」は行列の転置\n",
    "#triangle_nodes = np.array([[0,1,1,0],[0,0,1,0]])でもよいが、上のように点ごとに入力してから転置すると簡単\n",
    "#閉じた図形の場合、最初の点を最後にも入れる必要があることに注意\n",
    "\n",
    "print(triangle_nodes)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "このとき、この行列の第0行`triangle_nodes[0,:]`が $x$ 座標のリスト、第1行`triangle_nodes[1,:]`が $y$ 座標のリストに対応するため、三角形の描画のコードは次のようになります。"
   ]
  },
  {
   "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\")  #アスペクト比（縦横比）を1:1にする\n",
    "\n",
    "plt.plot(triangle_nodes[0,:],triangle_nodes[1,:],\"r-\")  #三角形の描画\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2. 家の描画\n",
    "\n",
    "続いて、三角形と四角形を組み合わせて家の図を描画してみましょう。\n",
    "\n",
    "考える三角形の頂点を $(0,3),(-3,2),(3,2)$、四角形の頂点を $(-2,2),(-2,0),(2,0),(2,2)$ とし、それぞれの情報を変数`roof_nodes`と`wall_nodes`に格納することにします。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\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,:],\"r-\")  #屋根の描画\n",
    "plt.plot(wall_nodes[0,:],wall_nodes[1,:],\"r-\")  #壁の描画\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 演習1\n",
    "\n",
    "自分なりの家の図を描画してください。屋根や壁の形を変えるほか、適当に窓やドアなどを追加すると良いです。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#演習1のコード\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "#ここに、コードを書く\n",
    "#roof_nodes、wall_nodesに加え、必要に応じてwindow_nodes、door_nodesなどを用意する"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. 線形変換\n",
    "\n",
    "与えられた点や図形に対して、**幾何変換**（幾何学的な変換）を行うことを考えます。\n",
    "\n",
    "変換前の点を $(x,y)$、変換後の点を $(x',y')$ とするとき、$2\\times 2$ 行列 $A$ を用いて\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",
    "\n",
    "と表されるのが**線形変換（linear transformation）**です。\n",
    "\n",
    "重要なこととして、上で考えたような図形を特徴付ける複数の点からなる行列（$2\\times n$ 行列）に対して $A$ を左から掛ければ、全ての点に対する線形変換、すなわち図形に対する線形変換を行うことができます。\n",
    "\n",
    "線形変換は様々に考えられますが、以下では重要なものを紹介します。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.1. 拡大・縮小変換\n",
    "\n",
    "**拡大・縮小変換**は、原点を中心に一定の倍率での拡大・縮小を行う線形変換です。\n",
    "\n",
    "$x$ 軸方向に $\\alpha$ 倍、$y$ 軸方向に $\\beta$ 倍する変換は、\n",
    "\n",
    "$$\n",
    "\\begin{pmatrix}\n",
    "x'\\\\\n",
    "y'\n",
    "\\end{pmatrix}\n",
    "=\n",
    "\\begin{pmatrix}\n",
    "\\alpha & 0\\\\\n",
    "0 & \\beta\n",
    "\\end{pmatrix}\n",
    "\\begin{pmatrix}\n",
    "x\\\\\n",
    "y\n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "と表されます。\n",
    "\n",
    "例として、1.1の三角形に対して $x$ 軸方向に $2$ 倍、$y$ 軸方向に $1.5$ 倍する変換を行うと、次のようになります。"
   ]
  },
  {
   "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",
    "new_triangle_nodes = A@triangle_nodes  #変換後の点からなる行列\n",
    "\n",
    "plt.plot(new_triangle_nodes[0,:],new_triangle_nodes[1,:],\"b-\")  #変換後の三角形の描画（青色）\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2. 回転変換\n",
    "\n",
    "**回転変換**は、原点を中心に一定の角度での回転を行う線形変換です。\n",
    "\n",
    "反時計回りに角度 $\\theta$（単位はラジアン）だけ回転する変換は、\n",
    "\n",
    "$$\n",
    "\\begin{pmatrix}\n",
    "x'\\\\\n",
    "y'\n",
    "\\end{pmatrix}\n",
    "=\n",
    "\\begin{pmatrix}\n",
    "\\cos\\theta & -\\sin\\theta\\\\\n",
    "\\sin\\theta & \\cos\\theta\n",
    "\\end{pmatrix}\n",
    "\\begin{pmatrix}\n",
    "x\\\\\n",
    "y\n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "と表されます。\n",
    "\n",
    "例として、1.1の三角形に対して反時計回りに $10$ 度だけ回転する変換を行うと、次のようになります。"
   ]
  },
  {
   "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",
    "theta = 10/180*np.pi  #度をラジアンに直す\n",
    "A = np.array([[np.cos(theta),-np.sin(theta)],[np.sin(theta),np.cos(theta)]])  #変換行列\n",
    "new_triangle_nodes = A@triangle_nodes  #変換後の点からなる行列\n",
    "\n",
    "plt.plot(new_triangle_nodes[0,:],new_triangle_nodes[1,:],\"b-\")  #変換後の三角形の描画（青色）\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.3. 対称変換\n",
    "\n",
    "**対称変換**は、原点を通るある直線に関して対称移動を行う線形変換です。\n",
    "\n",
    "特に、$x$ 軸に関して対称移動する変換は\n",
    "\n",
    "$$\n",
    "\\begin{pmatrix}\n",
    "x'\\\\\n",
    "y'\n",
    "\\end{pmatrix}\n",
    "=\n",
    "\\begin{pmatrix}\n",
    "1 & 0\\\\\n",
    "0 & -1\n",
    "\\end{pmatrix}\n",
    "\\begin{pmatrix}\n",
    "x\\\\\n",
    "y\n",
    "\\end{pmatrix},\n",
    "$$\n",
    "\n",
    "$y$ 軸に関して対称移動する変換は\n",
    "\n",
    "$$\n",
    "\\begin{pmatrix}\n",
    "x'\\\\\n",
    "y'\n",
    "\\end{pmatrix}\n",
    "=\n",
    "\\begin{pmatrix}\n",
    "-1 & 0\\\\\n",
    "0 & 1\n",
    "\\end{pmatrix}\n",
    "\\begin{pmatrix}\n",
    "x\\\\\n",
    "y\n",
    "\\end{pmatrix},\n",
    "$$\n",
    "\n",
    "直線 $y=x$ に関して対称移動する変換は\n",
    "\n",
    "$$\n",
    "\\begin{pmatrix}\n",
    "x'\\\\\n",
    "y'\n",
    "\\end{pmatrix}\n",
    "=\n",
    "\\begin{pmatrix}\n",
    "0 & 1\\\\\n",
    "1 & 0\n",
    "\\end{pmatrix}\n",
    "\\begin{pmatrix}\n",
    "x\\\\\n",
    "y\n",
    "\\end{pmatrix}\n",
    "$$\n",
    "\n",
    "と表されます。\n",
    "\n",
    "例として、1.1の三角形に対して $y$ 軸に関して対称移動する変換を行うと、次のようになります。"
   ]
  },
  {
   "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([[-1,0],[0,1]])  #変換行列\n",
    "new_triangle_nodes = A@triangle_nodes  #変換後の点からなる行列\n",
    "\n",
    "plt.plot(new_triangle_nodes[0,:],new_triangle_nodes[1,:],\"b-\")  #変換後の三角形の描画（青色）\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 演習2\n",
    "\n",
    "1.2の家（または演習1で考えた自分なりの家）に対して何かしらの拡大・縮小変換、回転変換、対称変換を一つずつ行い、変換前の家と合わせて四つの家を一つの図に描画してください。ただし、別々の色にすること。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#演習2のコード\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\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,:],\"r-\")\n",
    "plt.plot(wall_nodes[0,:],wall_nodes[1,:],\"r-\")\n",
    "\n",
    "#ここに、コードを書く\n",
    "#A、new_roof_nodes、new_wall_nodesを作成する\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 演習3（オプション）\n",
    "\n",
    "線形変換の一種である**せん断変換**についてWikipediaなどで調べた上で、1.2の家（または演習1で考えた自分なりの家）に対して何かしらのせん断変換を行い、変換前の家と変換後の家を一つの図に描画してください。ただし、別々の色にすること。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#演習3のコード"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 第10回レポート課題\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
}
