124 lines
4.3 KiB
Python
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)
|