# CAPSTONE TEST OUT CS101: BANANA ROTATING
CONTRIBUTER: Nguyễn Gia Minh
PROGRAMING LANGUAGE: Python(version 3.9.6)
OS TESTED: Windows 10(updated to the last version)
### HOW TO RUN PROGRAM:
#### This project is to rotating the banana in your screen
Download 2 files "screen" and "core" to your computer, extract the winrar.
Run the file "screen"
And then on your screen it will illustrate a banana rotating around a virtual object
# ALGORIGHTM:
```
If you concern about how the code works, there is a detail instruction here.
```
### Uderstand the banana appearance
<img src="https://t3.ftcdn.net/jpg/03/03/66/56/360_F_303665638_AvUUcS4St4a3zcqA4FoW0tCDyyo5RwYR.jpg" alt="logo" width="270" height="180">
###### (source: https://stock.adobe.com/vn/search/images?k=banana)
* The curve of the banana is mostly similar to the curve of a circle I will call it **Banana Curve** and its radius is **R1 = 2**. And if we cut the banana likes the next picture, we can see the surface inside the banana is a circle I will call it **Circle 2** and its radius is **R2**
<img src ="https://chuoihotblog.files.wordpress.com/2016/10/chuoi-hot-qua-chuoi-thuong-cat-doi.jpg" width='270'>
###### (sourse: https://chuoihotblog.wordpress.com/2016/10/26/qua-chuoi-hot-phan-biet-qua-chuoi-hot-va-qua-chuoi-thuong/)
* However, does not like the **R1** which is supposed to be a constant, the **R2** is distinguish in "different part of the banana" which I will call it **banana point**. So I can makes a mathatics function for changing of **R2**. It is hard to get the absolute function for a perfect banana, so I linearized the function to approach the approximate values.
* To make these linear system, I chose 5 point:$A(2,0.15),B(1.6,0.15),C(1.5,042),D(-1.4,0.5),E(-\sqrt{3},0.1)$. and I made linear functions which pass 2 point, respectively $AB,BC,CD,DE$
* $R2=f(bp) = \left\{\begin{array}{1}
0.15,(1.6<bp \leq 2) [1]\\
\frac{0.447-0.27* R2}{0.1},(1.5<bp\leq 1.6)[2]\\
\frac{2.676 - 0.16*R2}{5.8},(-1.4<bp\leq1.5)[3]\\
\frac{-7/25 +\sqrt{3} +0.8 *R2}{2*(\sqrt{3}-1.4)}
,(-\sqrt{3}\leq bp \leq -1.4)[4]
\end{array}\right.$
ps: **bp** meanse **banana point**
* It looks a little bit complicated but it is easy to understand if I visualise the chart of that function.
![]()
<img src ="https://i.imgur.com/Gyeyn3N.png" width='470'>
* the part [1] of the function which I color in red represents the banana head, it is approximately unchange in radius.
* the part [2] (blue),[3] (orange) and [4] (cyan) represent the body of the banana.
* The Max value of **R2** is 0.5 to make the banana apperance looks most realistic
* But why the limit of **banana point** is $\sqrt{3}$ and $2$. I will show it later.
* So now we want to draw the curve of the of the banana. As I said before, it is mostly like a curve of the circle, I will call that curve is the circle curve from the angle $0$ to $\frac{5\pi}{6}$. And its radius **R1=2**.
<img src ="https://i.imgur.com/ZW379wW.png" width='470'>
* the smaller pie of the circle is decided to be the **banana curve**. And this picture also demonstrates the answer for the question why the limit of **banana point** is $[-\sqrt{3},2]$. Because it is the projection of the **banana curve** to the coordinate system.
## core EXPLANATION
we are using the 3D space to draw the object so the coordinate will be like $[x,y,z]$
### 1. draw the circle with the center is banana point
* First, we have the define the vector and matrix that will contribute to create the circle.
* this vector to create the distance from the banana to the center of the coordinate system
* **circle center vector**= $[R1,0,0]$
<img src ="https://i.imgur.com/uutlgpy.png" width='470'>
* to create the circle, We have to rotate the vector which length is **R2** around the **banana point**. That vector will be called **circle point**. And the angle of rotating is control by a variable **$\phi$** . Then we have a function:
* **circle point**$=[R2*\cos{\phi},R2*\sin{\phi},0]$
* And the circle after being drawed have to move, so the fully circle cordinate will be call **circle**:
* **circle** $=$ **circle draw** + **circle center vector**
* After that, we add the **circle center vector** with **circle draw**, we can illustrate the circle location of the circle to the coordinate system.
* Then we move the **banana point to the next location** to repeat the step of roating cicle. And the function we use is the rotation of y-axis which I will call **rotating circle matrix**. In linear algebra, the rotation of y-axis is defined as:
* **rotating circle matrix** $=\begin{bmatrix}
\cos{\theta} & 0 & \sin{\theta}\\
0 & 1 & 0\\
-\sin{\theta} & 0 & cos{\theta}
\end{bmatrix}$
* with $\theta$ is the angle of the rotation, $\theta$ is limited in range$[0,\frac{5\pi}{6}]$ as we mentioned before. so we have to new equation for the program:
* this equation is to update the coordinate of banana point:
* **banana point** = **R2**$*cos{\theta}$
* And this eqution is to make the full banana:
* **banana** = **rotating circle matrix** $\cdot$ **circle** (this equation is not sufficent, more detail in the next step) equation[A]
* The speed of the angle $\theta$ and $\phi$ is controlled by 2 constants:
* **THETA PACE** = 0.04
* **PHI PACE** = 0.09
### 2.Make the movement:
<img src ="https://i.imgur.com/6dFPxGE.png" width='570'>
* we want the banana to spin around on at least two more axes for the animation. They were called **x rotating banana** and **z rotating banana** in the original code. So we define these rotating matrixes:
* **x rotating banana** $=\begin{bmatrix}
1 & 0 & 0\\
0 & \cos{A} & -\sin{A}\\
0&\sin{A} & cos{A}
\end{bmatrix}$
* **z rotating banana** $=\begin{bmatrix}
\cos{B} & -\sin{B} & 0\\
\sin{B} & cos{B} & 0\\
0 & 0 & 1
\end{bmatrix}$
* With **A**,**B** is the angle of the the movement. It is controlled by the speed which I'll call
* **A_PACE**$=\frac{\pi}{10}$
* **B_PACE**$=\frac{\pi}{20}$
* So the total movement occur when I make the dot product of these 2 matrixes:
* **move** = **x rotating rotating** **$\cdot$** **z rotating banana**
* Intergrate with the step of drawing the banana, we need a temporary variable to contant the dot product between **move** and **rotating circle matrix**, I will call
* **temporary** = **move** $\cdot$ **rotating circle matrix**
* The equation[A] is now updated to a new equation
* **banana** = **temporary** $\cdot$ **circle**
### 3.Surface Normal
* To make the luminance of the surface normal of the banana, I will call it **banana surface normal**. The **banana surface normal** is the intergration of all surface vector of the circle in side the banana which I will call **circle surface normal**.
<img src ="https://i.imgur.com/s69giLl.png" width='370'>
* As we can see, **circle surface normal** vector have the same direction with **circle draw** vector. So we have a equation.
* **circle surface normal** $=[cos{\phi},sin{\phi},0]$
* And also the ***circle surface normal** needs to be rotate to likes the circle.
* **banana surface normal** = **temporary** $\cdot$ **circle surface normal**.
If we define the screen
### 4.Drawing output:
* Now we have caculated all the point and the surface normal of the banana, so we needs 2 generators to install the cordination of each frame. I will call it the **cordinate 3D** and **surface normal 3D**.
<img src ="https://i.imgur.com/dCQKh4z.png" width='570'>
* In the computer, we define the x as the width, y as the height and z is the virtual depth. The banana needs to rotating around the the point **depth**$(0,0,6)$. So when we write the coordinate of the banana, we need to add **depth** with the previous coordinate of banana.
#### 5. core closing:
* So the funtion of the movement looks like this.(This block is just for reference, it does not show all how the code works):
```
While <all frames are not written down>:
creat a new frame
Draw banana (draw every cicle of the banana by using recursion) by recursion
record the value into the generators.
update value for the next frame
```
## screen EXPLANATION
### 1.Projection
* First we assign x,y,z value:
* $x,y,z=$**cordinate 3D**$_{frame}$
<img src ="https://i.imgur.com/5HSrbUQ.png" width='470'>
* To render a 3D object onto a 2D screen, We project each point (x,y,z) in 3D-space onto a plane located z’ units away from the viewer, so that the corresponding 2D position is (x’,y’). Since we’re looking from the side, We can only see the y and z axes, but the math works the same for the x axis (it cannot be shown on the picute). This projection is really easy to obtain: notice that the origin, the y-axis, and point (x,y,z) form a right triangle, and a similar right triangle is formed with (x’,y’,z’). Then, we apply the Thales theorism:
* ### $\frac{y'}{z'}=\frac{y}{z}$
* ### $<=>y'=\frac{y*z'}{z}$
* $z'$ the distance from the screen to the eyes, but in the normal screen, z' is unchange, so I rename and set a for it by **k1**$=45$. Similarly, we apply this equation to $x'$, so we have the coordinate on the screen of each point from the banana is:
* ### $(x',y')=(\frac{K1*x}{z},\frac{K1*y}{z})$
### 3. making 2D coordinate map
* First, I define **width**$=65$ for a square screen
*
### 3.Luminance
* To show the lumuniance, first we have to define the light direction. So we can assign the constant
* **light direction**$=[0,1,0]$
* We make the dot product between **light direction** and **banana surface normal** to get the **luminance** of each point of the banana.
* **luminace** $=$ **light direction** $\cdot$ **banana surface normal**
* **luminance** >0 when **banana surface normal** facing to the light direction and <0 when **banana surface normal** is not. However there are some point that is locating behind the banana but it the **luminance** below zeros. To solve this we can use the technique to compare the **z-buffer** with **ooz**:
* ### **ooz**$=\frac{1}{z}$
* **z-buffer** is an generator containing the value of the ooz. it set 0 for all values as default
* If the new ooz is higher than the value which has been already contained in the **z-buffer** then:
* **z-buffer**$_{frame,x',y'}$=**ooz**
### 4. output
* first I define string
* **shadow** = '.,-~:;=!*#$@'
* if we use calculus to solve the **luminance**, the max value of **luminance** is $\sqrt{2}$, so to do the index, we can multiply it by 8
* **l index** = int($8*$**luminance**)
* we need to make another generator to containing the output which we will show it on the screen, I will call it **output**. It is mostly similar to **z-buffer** but while the **z-buffer** contains the number, the **output** contains the string, it is set default with the space in it. As the same time we updating the new value of **z-buffer**, we also update the value of **output**
* **output**$_{frame,x',y'}=$ **shadow**$_{l\_index}$
# SOME CONTRAST OF THIS CODE
* This code is slow (about 2s) and lose a lot of ram than drawing in on a graphics software because I use a lot of generator and loops in my code
* the source code is long
* the banana shape is not perfect because I cannot create a appropriate math function to draw it
# REFERENCES
(Donut math: how donut.c works,https://www.a1k0n.net/2011/07/20/donut-math.html)
(Rotating matrix, https://en.wikipedia.org/wiki/Rotation_matrix)