{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "924a2a50",
   "metadata": {},
   "source": [
    "## Question 3 (10 marks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "2b3d1ba2",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "478bad7a",
   "metadata": {},
   "outputs": [],
   "source": [
    "points = np.load('data/points.npy').astype(np.uint8)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "e07b0285",
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_rotation_matrix(points, theta):\n",
    "    \"\"\"\n",
    "    Write a function compute_rotation_matrix(points, theta) to compute the rotation matrix in\n",
    "    homogeneous coordinate system to rotate a shape depicted with 2-dimensional (x,y) coordinates\n",
    "    points with an angle 𝜃 (theta in the definition) in the anticlockwise direction about the centre of the shape.\n",
    "\n",
    "    Parameters:\n",
    "    points: a 2-dimensional numpy array of data type uint8 with shape 𝑘 × 2. Each row\n",
    "    of points is a Cartesian coordinate (x, y).\n",
    "    \n",
    "    theta: a floating-point number denoting the angle of rotation in degree.\n",
    "    \n",
    "    Returns:\n",
    "    The expected output is a 2-dimensional numpy array of data type float64 with shape 3 × 3.\n",
    "    \"\"\"\n",
    "\n",
    "    # Convert theta from degrees to radians\n",
    "    theta_rad = np.radians(theta)\n",
    "\n",
    "    # Calculate the centre of the shape\n",
    "    centre = np.mean(points, axis=0)\n",
    "\n",
    "    # Define the translation matrices to move the centre of the shape to the origin and back\n",
    "    translation_to_origin = np.array([[1, 0, -centre[0]],\n",
    "                                      [0, 1, -centre[1]],\n",
    "                                      [0, 0, 1]], dtype=np.float64)\n",
    "\n",
    "    translation_back = np.array([[1, 0, centre[0]],\n",
    "                                 [0, 1, centre[1]],\n",
    "                                 [0, 0, 1]], dtype=np.float64)\n",
    "\n",
    "    # Define the rotation matrix about the origin\n",
    "    rotation = np.array([[np.cos(theta_rad), -np.sin(theta_rad), 0],\n",
    "                         [np.sin(theta_rad),  np.cos(theta_rad), 0],\n",
    "                         [0,                 0,                1]], dtype=np.float64)\n",
    "\n",
    "    # Combine the translation and rotation into a single transformation matrix\n",
    "    rotation_matrix = np.dot(np.dot(translation_back, rotation), translation_to_origin)\n",
    "    \n",
    "    return rotation_matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "16ef4247",
   "metadata": {},
   "outputs": [],
   "source": [
    "rotation_matrices = []\n",
    "\n",
    "for t in range(0, 365, 5):\n",
    "    rotation_matrices.append( compute_rotation_matrix(points, t) )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a130c201",
   "metadata": {},
   "source": [
    "## Save Output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "23967b5d",
   "metadata": {},
   "outputs": [],
   "source": [
    "np.save('data/question_3_rotation_matrices.npy', rotation_matrices)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a808d8a4",
   "metadata": {},
   "source": [
    "## Put students' implementations here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "b0836f8d",
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_rotation_matrix(points, theta):\n",
    "    # Convert points to float64\n",
    "    points = points.astype(np.float64)\n",
    "    # Calculate centre\n",
    "    centre = np.mean(points, axis=0)\n",
    "    # Compute rotation matrix\n",
    "    rotation_matrix = np.array([[np.cos(np.radians(theta)), -np.sin(np.radians(theta)), 0],\n",
    "                                [np.sin(np.radians(theta)), np.cos(np.radians(theta)), 0],\n",
    "                                [0, 0, 1]])\n",
    "    # Translation matrix to origin\n",
    "    translation_to_origin = np.array([[1, 0, -centre[0]],\n",
    "                                      [0, 1, -centre[1]],\n",
    "                                      [0, 0, 1]])\n",
    "    # Translation matrix to original position\n",
    "    translation_to_centre = np.array([[1, 0, centre[0]],\n",
    "                                         [0, 1, centre[1]],\n",
    "                                         [0, 0, 1]])\n",
    "    # Combine transformations with data type float64 \n",
    "    combined_matrix = np.dot(np.dot(translation_to_centre, rotation_matrix), translation_to_origin).astype(np.float64)\n",
    "    return combined_matrix\n",
    "\n",
    "    return 0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73b68192",
   "metadata": {},
   "source": [
    "## Test (Should output ALL PASS)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1c0a88a6",
   "metadata": {},
   "source": [
    "Restart and Run ALL for each submission"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "132d734b",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "73 PASS\n",
      "ALL PASS\n"
     ]
    }
   ],
   "source": [
    "n_pass = 0\n",
    "for t in range(0, 365, 5):\n",
    "    if np.allclose(compute_rotation_matrix(points, t), rotation_matrices[int(t / 5)]):\n",
    "        n_pass = n_pass + 1\n",
    "\n",
    "print(n_pass, \"PASS\")\n",
    "assert n_pass == len(rotation_matrices)\n",
    "print(\"ALL PASS\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0fac308a",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "what",
   "language": "python",
   "name": "what"
  },
  "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.16"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
