COMP 2012H Honors Object-Oriented Programming and Data Structures

Lab 5 Class, Object, Constructors and Destructor

Review


This lab is about class, object, constructor and destructor

A class is a user-defined type representing a set of objects with the same structure and behavior. Objects are variables of class type. Each object of a class has its own copies and values of its data members. All objects of a class share a common set of member functions. In addition, C++ allows access control to each data member and member function:

  • public: accessible to any functions (both member functions of the class or other functions)
  • private: accessible only to member functions of the class
  • protected: (will be discussed when we talk about inhertiance)

There are at least 4 types of member functions:

  • Constructors: used to create and initialize object.
    • They are special member functions having the same name as the class and they are used to initialize the data members of objects of the class.
    • They are automatically invoked when a class object is created.
    • Constructors must not specify a return type or explicitly return a value.
    • Can have many different versions, but different constructors should take different parameters.
  • Destructor: used to destruct class objects. It is needed only when objects contain dynamic data member(s).
  • Accessor: const member functions that inspect data members; they do not modify any data members though.
  • Mutator: will modify some data member(s).
The member functions may be defined
  • inside the class definition in a .h header file
  • outside the class definition in a .cpp source file. In that case, each function name must be prepended with the class name and the special class scope operator::.

Default Constructor

  • A default constructor is a constructor that is called with NO argument. E.g. X::X() for class X.
  • It is given by the compiler automatically if no constructor is defined and it only creates an object with enough space for the data members, but their initial values CANNOT be trusted.
  • If you overload the default constructor, you can specify default values as initial values for the data members.

Destructor

  • A destructor is a special member function of a class which has same name as the class and prefixed with a tilde (~).
  • It is executed whenever an object of its class goes out of scope or whenever the delete expression is applied to a pointer to the object of that class.
  • It can neither return a value nor can it take any parameters.
  • Destructor can be very useful for releasing resources.
Card image cap

Introduction

In this lab, you are going to create a very simple animated physics simulation of planetary bodies. The interaction of planets are simulated using a very rough approximation of Newtonian physics, and are drawn onto the console frame by frame.


How to use the program

Note that the character inputs to the program are case sensitive.

  1. Configure the positions and initial velocities of at most 10 planets.
    • Planets are added one by one
    • Enter 'Y' in the console to add a planet
    • Enter 'x y', the coordinates of the planet (e.g. '-1 1')
    • Enter 'vx vy', the initial velocity (e.g. '2 0')
    • Enter the mass of the planet
    • If no more planets are to be added, type anything else in the console during the add planet prompt.
  2. Set the font size of the console to 6 for perfect fullscreen display if necessary (see below).
  3. Start the animation by typing 'A'.
    • Type anything else to output the displacements of the planets frame by frame without animation. The printed values are the displacements rounded to the nearest integer. This will be used internally by ZINC for automated grading.

How to change the font size

To change the font size of the console on Mac, use shortcut: command -. For Windows, right click on the window title bar, select Properties -> Font and set the size (default: 16).
  1. Click to open menu, as shown below.
  2. Card image cap
  3. After selecting properties, navigate to the font tab and set the size, as shown below.
  4. Card image cap


Relevant Physics Background


Some backgrounds of physics are shown below. However, for those who do not have a physics and calculus background, you may want to skip them and use the given formula provided under each task to complete the lab.

Displacement, Velocity, Acceleration

The displacement vector $\vec{s}=(s_x,s_y)$ of an object is the location of the planet relative to the center of the grid. $s_x,s_y$ are the horizontal and vertical distances respectively, with up, right being the positive direction.

The velocity vector, \(\vec{v} = (v_x, v_y)\), is the change in displacement relative to time, and similarly the acceleration, \(\vec{a} = (a_x, a_y)\), is the change in velocity respect to time. We have $$\frac{d\vec{s}}{dt}=\vec{v}\phantom{ee}\frac{d\vec{v}}{dt}=\vec{a}$$ $$\frac{ds_x}{dt}=v_x\phantom{ee}\frac{ds_y}{dt}=v_y$$ $$\frac{dv_x}{dt}=a_x\phantom{ee}\frac{dv_y}{dt}=a_y$$

Gravitational Force

By Newton's Law of Universal Gravitation, the magnitude of the gravitational force, \(|\vec{F}|\) , between two bodies are both given by $$|\vec{F}| = G \frac{m_1m_2}{r^2}$$ where $m_1,m_2$ are the masses of the two objects, $r$ is the distance between the two objects, and $G$ is the gravitational constant. For our purposes, we can assume the units are normalized such that $G=1$, and the magnitude of the force would then be $$|\vec{F}|=\frac{m_1m_2}{r^2}$$ The gravitational force by Planet 2 on Planet 1, \(\vec{F}_{2\;on\;1}\), is obviously in the direction of the position of Planet 2 relative to Planet 1. We can derive \begin{align*} \vec{F}_{2\text{ on }1}&=\frac{m_1m_2}{r_{21}^2} \cdot \frac{\vec{s}_2 - \vec{s}_1}{|\vec{s}_2-\vec{s}_1|} \\ &=\frac{m_1m_2}{r_{21}^3} (\vec{s}_2-\vec{s}_1) \\ &=\frac{m_1m_2}{r_{21}^3} \cdot (s_{x2}-s_{x1},s_{y2}-s_{y1}) \end{align*}

Net Force and Acceleration

By Newton's Second Law, the acceleration on a body is related to the net force, \(\vec{F}_{net}\) , on the body $$\vec{F}_{net}=m\vec{a}$$ The net force is just the sum of all the forces on the body. The net force on the planets would then be the sum of forces by all the other planets \begin{align*} m_i\vec{a}_i = \vec{F}_{\text{net on }i} &= \sum_{\substack{0 \leq j < n \\ j \neq i}} \frac{m_jm_i}{r_{ji}^3}(\vec{s}_j - \vec{s}_i) \\ \therefore \vec{a}_i &= \sum_{\substack{0 \leq j < n \\ j \neq i}} \frac{m_j}{r_{ji}^3}(\vec{s}_j - \vec{s}_i) \\ &= \sum_{\substack{0 \leq j < n \\ j \neq i}} \frac{m_j}{\Big(\sqrt{(s_{xj}-s_{xi})^2+(s_{yj}-s_{yi})^2}\Big)^3}(\vec{s}_j - \vec{s}_i) \end{align*} The acceleration is related to the displacements in this fashion, but the acceleration is also the second derivative of the displacement. This is a second order differential equation, which is hard to solve in general.

Approximation of Displacement

The displacement of all the planets are to be approximated at regular time intervals of $\Delta t$ seconds. Intuitively, if $\Delta t \rightarrow 0$, we expect that the instantaneous velocity to be very very close in that time interval, and similarly for acceleration. In other words, the velocities and accelerations would be approximately uniform, which gives the approximations $$\vec{s}(t+\Delta t)=\vec{s}(t) + \Delta t \cdot \vec{v}(t)\phantom{eee}\vec{v}(t+\Delta t)=\vec{v}(t) + \Delta t \cdot \vec{a}(t)$$ where $\vec{a}(t)$ can be computed as before.

Whenever two planets come too close to each other (in our purposes $|\vec{s}_i-\vec{s}_j|<0.1$), a collision occurs. For simplicity, the collision is to be handled in this fashion:

  • If $m_i=m_j$, destroy (deactivate) both planets.
  • Otherwise, destroy the planet with the smaller mass.


Overview of Program & Implementation

In this lab, the codes for rendering and configuration of planets are already provided. You only need to implement the Planet class in Planet.cpp and the function do_single_iteration for an iteration of the simulation in Simulation.cpp.

Global Variables
  • const int FPS - How many frames per second in the animation.
  • const int STEPS - How many iterations of simulation per frame.
    • Note that STEPS * FPS would be the number of iterations per second.
  • const int MAX_PLANETS - The length of the array of planets.
  • Planet planets[MAX_PLANETS] - The array of planets.
Data Members of Planet class
  • bool activated - Whether the planet is enabled. It is unnecessary to perform calculations on disabled planets.
  • bool flag_deactivate - If this is flagged true, disable the planet later.
    • Directly setting activated = false may cause logical errors, as the attribute activated is itself used in the collision checking.
  • double x,y,vx,vy,ax,ay - The displacement, velocity and acceleration of the planet.
  • int mass - The mass of the planet.
  • int uid - The index of the planet in the array.
Member functions of Planet class
  • void determine_collision() - Determines the collision and updates flag_deactivate according to the collision rules.
  • void update_acceleration() - Computes the acceleration by the formula above.
  • void update_velocity() - Computes the velocity using the approximation method with acceleration.
  • void update_displacement() - Computes the displacement using the approximation method with velocity.
Simulation Global function
  • void do_single_iteration() - Runs a single iteration of the simulation.

Lab Work

Note: In order to avoid discrepancies of the output from your program with the demo, you should use the following conventions (unless explicitly stated otherwise):

  • Use the exact formulae with the same order of operations given in the tasks below.
    • e.g $z(x+y)$ and $zx+zy$ are mathematically equivalent
    • To ensure the output are the same, use $z(x+y)$ instead of $zx+zy$
  • Every for loop should proceed in ascending order.
Although ZINC compares the displacements of the planets rounded to the nearest integer, it is safer to use the same calculations to avoid discrepancies due to floating point errors.


Task 1 - Complete velocity and displacement update functions


Recall that STEPS * FPS are the number of iterations per second. Therefore $\Delta t = \frac{1}{STEPS \times FPS}$. So the approximation of displacement would be $$\vec{s}_{\text{new}}=\vec{s}(t+\Delta t) = \vec{s}(t) + \Delta t \cdot \vec{v}(t) = \vec{s} + \frac{\vec{v}}{STEPS \times FPS}$$ *** For those of you who are not familiar with Physics, please use the following formula to implement the member functions. *** $$s_{x\text{new}}=s_x + \frac{v_x}{STEPS \times FPS}$$ $$s_{y\text{new}}=s_y + \frac{v_y}{STEPS \times FPS}$$ The approximation of the velocity is similar. Use the operator += whenever possible.

void Planet::update_velocity();
void Planet::update_displacement();

Task 2 - Complete acceleration update functions


Recall that the acceleration vector of Planet $i$ is given by the formula $$\vec{a}_i = \sum_{\substack{0 \leq j < n \\ j \neq i}} \frac{m_j \cdot (\vec{s}_j - \vec{s}_i)}{r_{ji}^3}$$ *** For those of you who are not familiar with Physics, please use the following formula to implement the member function. *** $$a_{xi} = \sum_{\substack{0 \leq j < n \\ j \neq i}} \frac{m_j \cdot (s_{xj} - s_{xi})}{r_{ji}^3}$$ $$a_{yi} = \sum_{\substack{0 \leq j < n \\ j \neq i}} \frac{m_j \cdot (s_{yj} - s_{yi})}{r_{ji}^3}$$ where $r_{ij}=|\vec{s}_j - \vec{s}_i|$ is the distance between planets $i,j$. Use std::hypot in the header cmath to compute the distance, and use $r_{ji} \cdot r_{ji} \cdot r_{ji}$ to compute the cube of the length.

You should also check Planet::activated, inactive planets should not contribute any gravitational force towards the current planet.

void Planet::update_acceleration(); // Updates the acceleration of the planet

Task 3 - Handle collision detection of planets


Recall that we handle the collision in this fashion:

  • A collision occurs between planets $i,j$ whenever $r_{ij}=|\vec{s}_i-\vec{s}_j|<0.1$ (use std::hypot).
  • If collision occurs and $m_i=m_j$, destroy both planets.
  • If collision occurs and $m_i \neq m_j$, destroy the smaller planet.
It is unnecessary to check collision for inactive planets. Do not directly set Planet::activated to false to avoid logical errors. Flag Planet::flag_deactivate to true instead so the planet gets deactivated later.

void Planet::determine_collision();

Task 4 - Implement the iteration function


This function is in Simulation.cpp.

void do_single_iteration();

You should complete the body of this function, which does the following in order.

  1. Determine collisions for all activated planets.
  2. Deactivate all the planets that are flagged to be deactivated. Hint: commit_activations
  3. Update the accelerations of all activated planets.
  4. Update the velocities of all activated planets.
  5. Update the displacements of all activated planets.
Display functions are already implemented in the skeleton code Display.h. There are FPS frames in one second, and this function is called STEPS times every frame.

Resources & Sample I/O

Sample Inputs

Two body system with center of mass moving uniformly to the right
Y
0 0
0 0
4
Y
0 6
10 0
1
n
A
Three body system
Y
0 0
0 0
4
Y
0 6
10 0
1
Y
0 -6
-9 -1
1
n
A

Submission & Grading

  • Deadline: Friday, 22nd October 2021 23:59.
  • You may earn 1 point for each lab via Automated Grading on the ZINC Online Submission System.
  • Please check here for a usage overview of ZINC.
  • Include the source files Simulation.cpp and Planet.cpp and zip them as lab5.zip for submission to ZINC.
Page maintained by
Homepage