# 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)