Files
earth/earth.py
2024-09-29 01:45:51 -04:00

124 lines
4.3 KiB
Python

import curses
import numpy as np
import math
import time
# Define the rotation speed of the globe
ROTATION_SPEED = 0.02
# Define the radius of the globe (in terms of terminal characters)
RADIUS = 10
# Define the number of latitude and longitude lines for the wireframe
NUM_LATITUDE_LINES = 12
NUM_LONGITUDE_LINES = 24
# Define characters for drawing the wireframe
WIREFRAME_CHAR = ''
CONTINENT_CHAR = '' # Different character for continents outline
# A simplified list of latitude and longitude points for continents
# This is a minimal representation; a real globe would need a much larger dataset
CONTINENT_POINTS = [
# Example points for North America, Europe, Africa, etc.
(45, -100), (60, -100), (30, -90), # North America
(50, 0), (55, 10), (60, 20), # Europe
(0, 10), (-10, 20), (-30, 10), # Africa
(-20, -50), (-30, -60), (-10, -70), # South America
(10, 100), (20, 120), (-10, 130), # Asia
]
# Function to convert latitude and longitude into 3D points on the globe
def lat_lon_to_xyz(lat, lon, radius):
lat_rad = math.radians(lat)
lon_rad = math.radians(lon)
x = radius * math.cos(lat_rad) * math.cos(lon_rad)
y = radius * math.cos(lat_rad) * math.sin(lon_rad)
z = radius * math.sin(lat_rad)
return x, y, z
# Function to project 3D points to 2D terminal coordinates
def project(x, y, z, screen_width, screen_height, scale=1):
factor = scale / (z + 3)
proj_x = int(screen_width / 2 + x * factor * screen_width / 4)
proj_y = int(screen_height / 2 - y * factor * screen_height / 4)
return proj_x, proj_y
# Function to generate globe wireframe points
def generate_globe(radius, lat_lines, long_lines):
points = []
for lat in range(0, lat_lines + 1):
theta = lat * math.pi / lat_lines
for lon in range(0, long_lines + 1):
phi = lon * 2 * math.pi / long_lines
x = radius * math.sin(theta) * math.cos(phi)
y = radius * math.sin(theta) * math.sin(phi)
z = radius * math.cos(theta)
points.append((x, y, z))
return points
# Function to apply rotation to the globe
def rotate(point, angle_x, angle_y, angle_z):
x, y, z = point
# Rotation around X-axis
y, z = y * math.cos(angle_x) - z * math.sin(angle_x), y * math.sin(angle_x) + z * math.cos(angle_x)
# Rotation around Y-axis
x, z = x * math.cos(angle_y) + z * math.sin(angle_y), -x * math.sin(angle_y) + z * math.cos(angle_y)
# Rotation around Z-axis
x, y = x * math.cos(angle_z) - y * math.sin(angle_z), x * math.sin(angle_z) + y * math.cos(angle_z)
return x, y, z
# Main drawing function
def draw_globe(stdscr):
curses.curs_set(0) # Hide cursor
stdscr.nodelay(True)
stdscr.timeout(50)
screen_height, screen_width = stdscr.getmaxyx()
globe_points = generate_globe(RADIUS, NUM_LATITUDE_LINES, NUM_LONGITUDE_LINES)
angle_x = angle_y = angle_z = 0
# Convert continent points to 3D points
continent_points_3d = [lat_lon_to_xyz(lat, lon, RADIUS) for lat, lon in CONTINENT_POINTS]
while True:
stdscr.clear()
# Increment angles for rotation
angle_x += ROTATION_SPEED
angle_y += ROTATION_SPEED / 2 # Slow Y-axis rotation for realism
angle_z += ROTATION_SPEED / 4 # Slow Z-axis rotation for realism
# Draw the wireframe globe by rotating points and projecting them
for point in globe_points:
rotated_point = rotate(point, angle_x, angle_y, angle_z)
proj_x, proj_y = project(*rotated_point, screen_width, screen_height)
if 0 <= proj_x < screen_width and 0 <= proj_y < screen_height:
stdscr.addch(proj_y, proj_x, WIREFRAME_CHAR)
# Draw the continent outlines
for point in continent_points_3d:
rotated_point = rotate(point, angle_x, angle_y, angle_z)
proj_x, proj_y = project(*rotated_point, screen_width, screen_height)
if 0 <= proj_x < screen_width and 0 <= proj_y < screen_height:
stdscr.addch(proj_y, proj_x, CONTINENT_CHAR)
stdscr.refresh()
try:
key = stdscr.getch()
if key == ord('q'):
break # Quit the application
except Exception:
pass
time.sleep(0.05)
# Main entry point for curses wrapper
if __name__ == "__main__":
curses.wrapper(draw_globe)