{ "cells": [ { "cell_type": "markdown", "id": "889cc4ff", "metadata": {}, "source": [ "# Object Oriented Programming" ] }, { "cell_type": "markdown", "id": "60fc39c3", "metadata": {}, "source": [ "Object oriented programming is a method of implementation in which\n", "\n", "1. programs are organized as cooperative collections of *objects*,\n", "\n", "2. each of which represents an instance of some *class*,\n", "\n", "3. and whose classes are all members of a *hierarchy* of classes united via inheritance relationships." ] }, { "cell_type": "markdown", "id": "75fe2661", "metadata": {}, "source": [ "# Points in the Plane" ] }, { "cell_type": "markdown", "id": "6e646083", "metadata": {}, "source": [ "We define a simple class to store coordinates of a point in the plane." ] }, { "cell_type": "code", "execution_count": 1, "id": "41ff1705", "metadata": {}, "outputs": [], "source": [ "class Point(object):\n", " \"\"\"\n", " Stores a point in the plane.\n", " \"\"\"\n", " def __init__(self, x=0, y=0):\n", " \"\"\"\n", " Defines the coordinates.\n", " \"\"\"\n", " self.xpt = x\n", " self.ypt = y\n", "\n", " def __str__(self):\n", " \"\"\"\n", " Returns the string representation.\n", " \"\"\"\n", " return '(' + str(self.xpt) \\\n", " + ', ' \\\n", " + str(self.ypt) + ')'\n", "\n", " def __repr__(self):\n", " \"\"\"\n", " Returns the representation.\n", " \"\"\"\n", " return self.__str__() # same as string representation" ] }, { "cell_type": "markdown", "id": "9b528bfe", "metadata": {}, "source": [ "To test the class we instantiate two points." ] }, { "cell_type": "code", "execution_count": 2, "id": "21dd5b5d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "p = (0, 0)\n", "q = (3, 4)\n" ] } ], "source": [ "first = Point()\n", "print('p =', first)\n", "second = Point(3, 4)\n", "print('q =', second)" ] }, { "cell_type": "markdown", "id": "fa8b31f6", "metadata": {}, "source": [ "Inheriting from the class Point, we extend a point with a canvas\n", "data attribute and with a method to draw the point on the canvas." ] }, { "cell_type": "code", "execution_count": 3, "id": "eaa0c468", "metadata": {}, "outputs": [], "source": [ "class ShowPoint(Point):\n", " \"\"\"\n", " Extends the class Point\n", " with a draw method on a Tkinter Canvas.\n", " \"\"\"\n", " def __init__(self, cnv, x=0, y=0):\n", " \"\"\"\n", " Defines the coordinates (x, y)\n", " and stores the canvas cnv.\n", " \"\"\"\n", " Point.__init__(self, x, y)\n", " self.canvas = cnv\n", "\n", " def draw(self):\n", " \"\"\"\n", " Draws the point on canvas.\n", " \"\"\"\n", " (xpt, ypt) = (self.xpt, self.ypt)\n", " self.canvas.create_oval(xpt-3, ypt-3, \\\n", " xpt+3, ypt+3, fill='SkyBlue2')" ] }, { "cell_type": "markdown", "id": "534c970d", "metadata": {}, "source": [ "To test the ``ShowPoint``, we pop a window with a canvas of 10 points with random coordinates." ] }, { "cell_type": "code", "execution_count": 4, "id": "e003bacb", "metadata": {}, "outputs": [], "source": [ "from tkinter import Tk, Canvas\n", "from random import randint" ] }, { "cell_type": "code", "execution_count": 5, "id": "bcded2fb", "metadata": {}, "outputs": [], "source": [ "top = Tk()\n", "top.geometry(\"400x400\")\n", "dim = 400\n", "cnv = Canvas(top, width=dim, height=dim)\n", "cnv.pack()\n", "points = []\n", "for _ in range(10):\n", " xrd = randint(6, dim-6)\n", " yrd = randint(6, dim-6)\n", " points.append(ShowPoint(cnv, xrd, yrd))\n", "for point in points:\n", " point.draw()\n", "top.mainloop()" ] }, { "cell_type": "markdown", "id": "c39abca6", "metadata": {}, "source": [ "# Lines" ] }, { "cell_type": "markdown", "id": "5f0c09f1", "metadata": {}, "source": [ "We define a line as a point and a direction,\n", "inheriting from the class Point.\n", "The line is a callable object,\n", "evaluating the line yields a point on the line." ] }, { "cell_type": "code", "execution_count": 6, "id": "566dae00", "metadata": {}, "outputs": [], "source": [ "from math import cos, sin" ] }, { "cell_type": "code", "execution_count": 7, "id": "ead80320", "metadata": {}, "outputs": [], "source": [ "class Line(Point):\n", " \"\"\"\n", " A line is a base point and\n", " a direction angle.\n", " \"\"\"\n", " def __init__(self, x=0, y=0, a=0):\n", " \"\"\"\n", " Defines base point and angle.\n", " \"\"\"\n", " Point.__init__(self, x, y)\n", " self.angle = a\n", "\n", " def __str__(self):\n", " \"\"\"\n", " Returns the string representation.\n", " \"\"\"\n", " strp = Point.__str__(self)\n", " stra = ', angle = ' + str(self.angle)\n", " return strp + stra\n", "\n", " def __repr__(self):\n", " \"\"\"\n", " Returns the representation.\n", " \"\"\"\n", " return self.__str__()\n", "\n", " def __call__(self, argt):\n", " \"\"\"\n", " Returns a new point on the line.\n", " \"\"\"\n", " rxt = self.xpt + argt*cos(self.angle)\n", " ryt = self.ypt + argt*sin(self.angle)\n", " return Point(rxt, ryt)" ] }, { "cell_type": "raw", "id": "bf9dab6b", "metadata": {}, "source": [ "To test the class, we make a line and sample points from the line." ] }, { "cell_type": "code", "execution_count": 8, "id": "8e62eaa7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "the default line : (0, 0), angle = 0\n", "some point on it : (5.0, 0.0)\n", "a vertical line : (3, 4), angle = 1.5707963267948966\n", " that passes through (3.0, 4.0)\n", "another point on it is (3.0000000000000004, 8.0)\n" ] } ], "source": [ "first = Line()\n", "print('the default line :', first)\n", "print('some point on it :', first(5))\n", "from math import pi\n", "second = Line(3, 4, pi/2)\n", "print('a vertical line :', second)\n", "print(' that passes through', second(0))\n", "apt = second(4)\n", "print('another point on it is', apt)" ] }, { "cell_type": "markdown", "id": "760669cb", "metadata": {}, "source": [ "Inheriting from the class Line, we extend a point with a canvas\n", "data attribute and with a method to draw a line on the canvas." ] }, { "cell_type": "code", "execution_count": 9, "id": "a56235e2", "metadata": {}, "outputs": [], "source": [ "class ShowLine(Line, ShowPoint):\n", " \"\"\"\n", " Extends the Line class with a draw method.\n", " \"\"\"\n", " def __init__(self, c, d, x=0, y=0, a=0):\n", " \"\"\"\n", " Defines the line through the point\n", " (x, y), with angle a and stores the\n", " canvas c of dimension d.\n", " \"\"\"\n", " Line.__init__(self, x, y, a)\n", " ShowPoint.__init__(self, c, x, y)\n", " self.dimension = d\n", "\n", " def draw(self):\n", " \"\"\"\n", " Draws the line on canvas.\n", " \"\"\"\n", " ShowPoint.draw(self)\n", " cnv = self.canvas\n", " (xpt, ypt) = (self.xpt, self.ypt)\n", " dmx = self.dimension - xpt\n", " csa = cos(self.angle)\n", " if csa + 1.0 != 1.0:\n", " pt1 = Line.__call__(self, dmx/csa)\n", " cnv.create_line(xpt, ypt, pt1.xpt, pt1.ypt)\n", " pt2 = Line.__call__(self, -xpt/csa)\n", " cnv.create_line(pt2.xpt, pt2.ypt, xpt, ypt)\n", " else: # vertical line\n", " cnv.create_line(xpt, 0, xpt, self.dimension)" ] }, { "cell_type": "markdown", "id": "95b6e903", "metadata": {}, "source": [ "As a test, we draw 11 random lines on a canvas in a Tkinter window." ] }, { "cell_type": "code", "execution_count": 10, "id": "3e3e129d", "metadata": {}, "outputs": [], "source": [ "from random import uniform" ] }, { "cell_type": "code", "execution_count": 11, "id": "eaab2695", "metadata": {}, "outputs": [], "source": [ "top = Tk()\n", "top.geometry(\"400x400\")\n", "dim = 400\n", "cnv = Canvas(top, width=dim, height=dim)\n", "cnv.pack()\n", "lines = [ShowLine(cnv, dim, 100, 300, pi/2)]\n", "for _ in range(10):\n", " xrd = randint(6, dim-6)\n", " yrd = randint(6, dim-6)\n", " rnd = uniform(0, 2*pi)\n", " lines.append(ShowLine(cnv, dim, xrd, yrd, rnd))\n", "for line in lines:\n", " line.draw()\n", "top.mainloop()" ] }, { "cell_type": "markdown", "id": "54468015", "metadata": {}, "source": [ "# Parabolas" ] }, { "cell_type": "markdown", "id": "ce535c27", "metadata": {}, "source": [ "Given a point (the focus) and a line (the directrix),\n", "a parabola consists of all points that lie as far from\n", "the focus as from the directrix.\n", "The directrix is inherited from the class Line and\n", "the focus is the other data attribute." ] }, { "cell_type": "code", "execution_count": 12, "id": "ff506d26", "metadata": {}, "outputs": [], "source": [ "class Parabola(Line):\n", " \"\"\"\n", " A parabola is defined by a line,\n", " its directrix and a point, its focus.\n", " \"\"\"\n", " def __init__(self, px, py, agl, fx, fy):\n", " \"\"\"\n", " Defines the line at (px, py)\n", " and angle agl and focus (fx, fy).\n", " \"\"\"\n", " Line.__init__(self, px, py, agl)\n", " self.focus = Point(fx, fy)\n", "\n", " def __str__(self):\n", " \"\"\"\n", " Returns the string representation.\n", " \"\"\"\n", " strfocus = str(self.focus)\n", " line = Line.__str__(self)\n", " result = 'focus : ' + strfocus\n", " result += ', directrix : ' + line\n", " return result\n", "\n", " def __call__(self, t):\n", " \"\"\"\n", " Returns a point on the parabola\n", " as far from the focus and the point\n", " obtained by evaluating the directrix.\n", " \"\"\"\n", " line = Line.__call__(self, t)\n", " (fcx, fcy) = (self.focus.xpt, self.focus.ypt)\n", " disc = 2*(fcx - line.xpt)*(line.ypt - self.ypt) \\\n", " - 2*(fcy - line.ypt)*(line.xpt - self.xpt)\n", " rh1 = fcx**2 + fcy**2 - line.xpt**2 - line.ypt**2\n", " if disc + 1.0 != 1.0:\n", " rh2 = line.xpt*(line.xpt - self.xpt) \\\n", " + line.ypt*(line.ypt - self.ypt)\n", " sdx = (rh1*(line.ypt - self.ypt) \\\n", " - 2*rh2*(fcy - line.ypt))/float(disc)\n", " sdy = (2*(fcx - line.xpt)*rh2 \\\n", " - (line.xpt - self.xpt)*rh1)/float(disc)\n", " else:\n", " from math import exp, pi\n", " line = Line.__call__(self, exp(pi))\n", " disc = 2*(fcx - line.xpt)*(line.ypt - self.ypt) \\\n", " - 2*(fcy - line.ypt)*(line.xpt - self.xpt)\n", " rh1 = fcx**2 + fcy**2 - line.xpt**2 - line.ypt**2\n", " rh2 = line.xpt*(line.xpt - self.xpt) \\\n", " + line.ypt*(line.ypt - self.ypt)\n", " sdx = (rh1*(line.ypt - self.ypt) \\\n", " - 2*rh2*(fcy - line.ypt))/float(disc)\n", " sdy = (2*(fcx - line.xpt)*rh2 \\\n", " - (line.xpt - self.xpt)*rh1)/float(disc)\n", " return Point(sdx, sdy)" ] }, { "cell_type": "markdown", "id": "f649c18b", "metadata": {}, "source": [ "We test the evaluation on an instance of a parabola." ] }, { "cell_type": "code", "execution_count": 13, "id": "01d167f7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "instantiating a parabola ...\n", "focus : (10, 0), directrix : (3, 4), angle = -1.23\n", "a point on the parabola : (7.214603164135126, 1.2505555372364714)\n" ] } ], "source": [ "print('instantiating a parabola ...')\n", "prb = Parabola(3, 4, -1.23, 10, 0)\n", "print(prb)\n", "point = prb(4)\n", "print('a point on the parabola :', point)" ] }, { "cell_type": "markdown", "id": "37c31cf3", "metadata": {}, "source": [ "To show a parabola on canvas, we extend the object parabola with a canvas\n", "and a method to draw the parabola on canvas." ] }, { "cell_type": "code", "execution_count": 14, "id": "68d1470c", "metadata": {}, "outputs": [], "source": [ "class ShowParabola(Parabola, ShowLine):\n", " \"\"\"\n", " Extends the Parabola class with a draw method.\n", " \"\"\"\n", " def __init__(self, c, d, x, y, a, fx, fy):\n", " \"\"\"\n", " Defines the parabola with directrix the line\n", " at base point (x, y), angle a, and the focus\n", " with coordinates (fx, fy).\n", " Stores the canvas c of dimension d.\n", " \"\"\"\n", " Parabola.__init__(self, x, y, a, fx, fy)\n", " ShowLine.__init__(self, c, d, x, y, a)\n", "\n", " def draw_focus(self):\n", " \"\"\"\n", " Draws the focus on canvas.\n", " \"\"\"\n", " (fxp, fyp) = (self.focus.xpt, self.focus.ypt)\n", " self.canvas.create_oval(fxp-3, \\\n", " fyp-3, fxp+3, fyp+3, fill='red')\n", "\n", " def draw(self):\n", " \"\"\"\n", " Draws the parabola on canvas.\n", " \"\"\"\n", " ShowLine.draw(self)\n", " self.draw_focus()\n", " for tpt in range(-1000, 1000):\n", " prb = Parabola.__call__(self, tpt)\n", " self.canvas.create_oval(prb.xpt-1, \\\n", " prb.ypt-1, prb.xpt+1, prb.ypt+1, \\\n", " fill='SkyBlue2')" ] }, { "cell_type": "markdown", "id": "8d5b6aac", "metadata": {}, "source": [ "Let us look at a random parabola." ] }, { "cell_type": "code", "execution_count": 15, "id": "0b6af9c1", "metadata": {}, "outputs": [], "source": [ "top = Tk()\n", "top.geometry(\"400x400\")\n", "dim = 400\n", "cnv = Canvas(top, width=dim, height=dim)\n", "cnv.pack()\n", "from random import seed\n", "seed(201907)\n", "(xbs, ybs) = (randint(6, dim-6), randint(6, dim-6))\n", "agl = uniform(0, 2*pi)\n", "(fpx, fpy) = (randint(6, dim-6), randint(6, dim-6))\n", "pbl = ShowParabola(cnv, dim, xbs, ybs, agl, fpx, fpy)\n", "pbl.draw()\n", "top.mainloop()" ] }, { "cell_type": "code", "execution_count": null, "id": "e50b44cc", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.10.10" } }, "nbformat": 4, "nbformat_minor": 5 }