#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <SPI.h>

#define TFT_CS     10
#define TFT_RST    8
#define TFT_DC     9

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

// Define colors (16-bit RGB values)
uint16_t rainbow_colors[] = {
  ILI9341_RED, 
  ILI9341_ORANGE, 
  ILI9341_YELLOW, 
  ILI9341_GREEN, 
  ILI9341_BLUE, 
  ILI9341_MAGENTA, 
  ILI9341_CYAN
};
int color_index = 0;

int r_big = 150; // Initial large radius
int r_small = 50; // Smaller circle radius

void setup() {
  tft.begin();
  tft.setRotation(3); // Set the rotation as needed
  tft.fillScreen(ILI9341_BLACK);
}

void drawHypocycloid(int r_big, int r_small) {
  int centerX = tft.width() / 2;
  int centerY = tft.height() / 2;
  float angle = 0;
  float maxAngle = 360 * (r_big / gcd(r_big, r_small));
  int oldX = centerX + (r_big - r_small) * cos(0);
  int oldY = centerY + (r_big - r_small) * sin(0);

  while (angle <= maxAngle) {
    float radian = angle * PI / 180;
    float big_radian = radian * r_small / r_big;
    int x = centerX + (r_big - r_small) * cos(big_radian);
    int y = centerY + (r_big - r_small) * sin(big_radian);
    
    tft.drawLine(oldX, oldY, x, y, rainbow_colors[color_index]);
    oldX = x;
    oldY = y;
    
    color_index = (color_index + 1) % 7;
    angle += 1;

    delay(10); // Add a small delay for animation effect
  }
}

void displayText() {
  tft.setTextColor(ILI9341_YELLOW); // Set text color to yellow
  tft.setTextSize(2); // Set text size (adjust as needed)
  tft.setCursor(10, tft.height() - 30); // Set cursor position (bottom left)
  tft.print("code by Arvind");
}

void drawConcentricCircles() {
  int centerX = tft.width() / 2;
  int centerY = tft.height() / 2;
  int radius = 150; // Starting radius
  int delayTime = 200 * 4 / 3; // Decrease speed by one-third

  // Draw circles with decreasing radii
  while (radius > 0) {
    tft.drawCircle(centerX, centerY, radius, rainbow_colors[color_index]);
    color_index = (color_index + 1) % 7; // Cycle through the rainbow colors
    radius -= 20; // Reduce the radius by 20 pixels
    delay(delayTime); // Add a small delay to see the animation effect
  }
  
  // Draw circles with increasing radii
  radius = 20; // Starting radius for increasing circles
  while (radius <= 150) {
    tft.drawCircle(centerX, centerY, radius, rainbow_colors[color_index]);
    color_index = (color_index + 1) % 7; // Cycle through the rainbow colors
    radius += 20; // Increase the radius by 20 pixels
    delay(delayTime); // Add a small delay to see the animation effect
  }
}

void drawConcentricSquares() {
  int centerX = tft.width() / 2;
  int centerY = tft.height() / 2;
  int sideLength = 150; // Starting side length
  int delayTime = 200 * 4 / 3; // Decrease speed by one-third

  // Draw squares with decreasing side lengths
  while (sideLength > 0) {
    tft.drawRect(centerX - sideLength / 2, centerY - sideLength / 2, sideLength, sideLength, rainbow_colors[color_index]);
    color_index = (color_index + 1) % 7; // Cycle through the rainbow colors
    sideLength -= 20; // Reduce the side length by 20 pixels
    delay(delayTime); // Add a small delay to see the animation effect
  }
  
  // Draw squares with increasing side lengths
  sideLength = 20; // Starting side length for increasing squares
  while (sideLength <= 150) {
    tft.drawRect(centerX - sideLength / 2, centerY - sideLength / 2, sideLength, sideLength, rainbow_colors[color_index]);
    color_index = (color_index + 1) % 7; // Cycle through the rainbow colors
    sideLength += 20; // Increase the side length by 20 pixels
    delay(delayTime); // Add a small delay to see the animation effect
  }
}

void drawConcentricTriangles() {
  int centerX = tft.width() / 2;
  int centerY = tft.height() / 2;
  int sideLength = 150; // Starting side length
  int delayTime = 200 * 4 / 3; // Decrease speed by one-third

  // Draw triangles with decreasing side lengths
  while (sideLength > 0) {
    drawTriangle(centerX, centerY, sideLength, rainbow_colors[color_index]);
    color_index = (color_index + 1) % 7; // Cycle through the rainbow colors
    sideLength -= 20; // Reduce the side length by 20 pixels
    delay(delayTime); // Add a small delay to see the animation effect
  }
  
  // Draw triangles with increasing side lengths
  sideLength = 20; // Starting side length for increasing triangles
  while (sideLength <= 150) {
    drawTriangle(centerX, centerY, sideLength, rainbow_colors[color_index]);
    color_index = (color_index + 1) % 7; // Cycle through the rainbow colors
    sideLength += 20; // Increase the side length by 20 pixels
    delay(delayTime); // Add a small delay to see the animation effect
  }
}

void drawTriangle(int centerX, int centerY, int sideLength, uint16_t color) {
  int halfSide = sideLength / 2;
  int height = (sqrt(3) / 2) * sideLength;

  int x1 = centerX;
  int y1 = centerY - height / 2;

  int x2 = centerX - halfSide;
  int y2 = centerY + height / 2;

  int x3 = centerX + halfSide;
  int y3 = centerY + height / 2;

  tft.drawLine(x1, y1, x2, y2, color);
  tft.drawLine(x2, y2, x3, y3, color);
  tft.drawLine(x3, y3, x1, y1, color);
}

int gcd(int a, int b) {
  while (b != 0) {
    int temp = b;
    b = a % b;
    a = temp;
  }
  return a;
}

void loop() {
  // Draw 5 rainbow circles with decreasing radii
  tft.fillScreen(ILI9341_BLACK); // Clear the screen at the beginning of each drawing
  int radius_decrement = 25; // Radius decrement value for each subsequent circle
  int current_radius = r_big; // Start with the initial radius

  // Draw 5 circles with decreasing radius
  for (int i = 0; i < 5; i++) {
    drawHypocycloid(current_radius, r_small);
    current_radius -= radius_decrement; // Reduce the radius for the next circle
    delay(1000); // Pause before drawing the next circle
  }

  displayText(); // Display the text "code by Arvind" after drawing circles
  delay(2000); // Pause before clearing the screen and starting new shapes

  // Draw concentric circles
  tft.fillScreen(ILI9341_BLACK); // Clear the screen
  drawConcentricCircles();
  
  // Pause before clearing the screen and drawing squares
  delay(1000); 
  tft.fillScreen(ILI9341_BLACK); // Clear the screen

  // Draw concentric squares
  drawConcentricSquares();

  // Pause before clearing the screen and drawing triangles
  delay(1000); 
  tft.fillScreen(ILI9341_BLACK); // Clear the screen

  // Draw concentric triangles
  drawConcentricTriangles();

  // Display the final message after all animations
  tft.fillScreen(ILI9341_BLACK); // Clear the screen
  int centerX = tft.width() / 2;
  int centerY = tft.height() / 2;
  tft.setTextColor(ILI9341_WHITE);
  tft.setTextSize(2);
  tft.setCursor(centerX - 120, centerY - 20); // Adjust position as needed
  tft.print("THIS IS REDUCING AND");
  tft.setCursor(centerX - 120, centerY);
  tft.print("ENLARGING SHAPES CREATED");
  tft.setCursor(centerX - 120, centerY + 20);
  tft.print("BY ARVIND PATIL ON 4/8/24");
  tft.setCursor(centerX - 120, centerY + 60);
  tft.print("https://wokwi.com/projects/405366120965295105");

  // Pause for 5 seconds
  delay(5000); 
  tft.fillScreen(ILI9341_BLACK); // Clear the screen

  // Restart the loop
}