still updating the 3d video

This commit is contained in:
2025-07-08 15:26:33 +03:00
parent 2532bf6219
commit a565cd67e1
14 changed files with 1180 additions and 150 deletions

View File

@@ -1,40 +1,30 @@
# Enhanced 3D Video Animation Feature
# Professional Google Earth-Style 3D Video Animation
## Overview
The Enhanced 3D Video Animation feature generates professional, Google Earth-style video animations from GPS route data with spectacular space entry sequences. This upgraded system creates cinematic flythrough experiences starting from space and descending to follow the route with dynamic camera movement, realistic perspective, and advanced visual effects.
The Professional Google Earth-Style 3D Video Animation feature generates cinematic, high-quality video animations from GPS route data with realistic space entry sequences. This system creates authentic Google Earth-style visuals with professional terrain rendering, atmospheric effects, and spectacular space-to-Earth transitions.
## Core Enhancements
## Major Visual Enhancements
### Space Entry Sequence (NEW!)
- **Spectacular Entry from Space**: 3-second cinematic descent from 50km altitude
- **Smooth Space-to-Earth Transition**: Seamless transition from space view to aerial following
- **Earth Curvature Effects**: Realistic Earth curvature visible at high altitudes
- **Atmospheric Layers**: Progressive atmospheric effects during descent
- **Route Identification**: Route becomes visible and highlighted during descent
### Realistic Google Earth Visuals
- **Authentic Earth Sphere Rendering**: Realistic planetary view from space with proper curvature
- **Professional Terrain Textures**: Multi-layer terrain with forests, mountains, plains, deserts, and water bodies
- **Geographic Feature Simulation**: Coastlines, rivers, and landmasses with fractal-like detail
- **Atmospheric Scattering**: Realistic atmospheric effects and color gradients
- **Cloud Layer Rendering**: Dynamic cloud formations with proper shadows
### Advanced Camera System
- **Improved Aerial Perspective**: Camera height optimized for 1000-3000m range
- **Dynamic Camera Following**: Intelligent camera positioning that follows the route
- **Speed-Adaptive Look-Ahead**: Camera direction adjusts based on vehicle speed
- **Smooth Camera Transitions**: Fluid camera movements with momentum
- **Enhanced Perspective Offset**: Camera positioned for optimal aerial viewing angles
- **Dynamic Height & Tilt**: Camera height and angle adapt to terrain and speed
### Enhanced Space Entry Sequence
- **Spectacular Space View**: Authentic space background with star fields and Earth sphere
- **Realistic Atmospheric Entry**: Progressive transition through atmospheric layers
- **Earth's Terminator Line**: Day/night boundary visible at high altitudes
- **Professional UI**: Google Earth-style information panels and progress indicators
- **Cinematic Descent**: Smooth altitude progression from 50km to route level
### Google Earth-Style Perspective
- **True 3D Projection**: Proper field-of-view perspective projection
- **Depth-Aware Rendering**: Objects rendered in correct Z-order
- **Enhanced Aerial Views**: Optimized 1000-3000m altitude for perfect aerial perspective
- **Realistic Elevation**: Enhanced terrain with multi-layered elevation simulation
- **Atmospheric Perspective**: Distance fog and haze effects for depth
- **Terrain Grid**: Perspective grid for enhanced depth perception
### Enhanced Visual Effects
- **Space-to-Earth Transition**: Spectacular entry sequence with space background
- **Multi-Layer Terrain**: Realistic terrain with varied colors and textures
- **Gradient Backgrounds**: Dynamic space-to-sky-to-terrain transitions
- **Enhanced Route Visualization**: Depth-based thickness and opacity
- **Advanced Markers**: Multi-layer current position with shadows and glows
- **Direction Indicators**: Speed-based directional arrows
### Advanced Terrain System
- **Multi-Octave Terrain Generation**: Realistic landscape using multiple noise layers
- **Geographic Coordinate Influence**: Terrain varies based on actual GPS coordinates
- **Atmospheric Perspective**: Distance-based color shifts and haze effects
- **Cloud Shadow Mapping**: Realistic shadow patterns on terrain
- **Enhanced Color Palette**: Professional color schemes for different terrain types
### Professional UI Elements
- **Information Panel**: Speed, bearing, altitude, time, and progress with gradients
@@ -48,11 +38,14 @@ The Enhanced 3D Video Animation feature generates professional, Google Earth-sty
- **Frame Rate**: 30 FPS (smooth motion)
- **Format**: MP4 video (universal compatibility)
- **Compression**: MP4V codec optimized for quality
- **Space Entry**: 3-second descent from 50km altitude
- **Visual Quality**: Professional Google Earth-style rendering
- **Space Entry**: 3-second descent from 50km altitude with realistic visuals
- **Camera Height**: 1000-3000m (dynamic aerial perspective)
- **View Distance**: 3000m ahead (enhanced for aerial views)
- **Field of View**: 75° (optimized for aerial perspective)
- **Tilt Angle**: 65-73° (dynamic for terrain following)
- **Terrain Detail**: Multi-layer realistic terrain with 6+ terrain types
- **Color Depth**: Professional color palette with atmospheric effects
- **Entry Altitude Range**: 50km → 2km (space to aerial transition)
## Advanced Animation Features
@@ -226,14 +219,18 @@ Metadata Addition → File Output
1. **Space View (0-1 seconds)**: Starts from 50km altitude with black space background and Earth curvature
2. **Atmospheric Entry (1-2 seconds)**: Gradual transition showing atmospheric layers and blue sky emergence
3. **Route Approach (2-3 seconds)**: Descent to 2km altitude with route becoming visible and highlighted
4. **Aerial Following (3+ seconds)**: Seamless transition to dynamic camera following at optimal aerial height
4. **Transition Bridge (3-3.5 seconds)**: Smooth bridge frame announcing route start
5. **Aerial Following (3.5+ seconds)**: Seamless transition to dynamic camera following at optimal aerial height
### Technical Implementation
- **Altitude Range**: 50,000m → 2,000m → 1,000-3,000m (dynamic)
- **Descent Curve**: Cubic ease-out for natural deceleration
- **Camera Transition**: Smooth movement from center overview to route start
- **Transition Bridge**: Dedicated frame for smooth space-to-route handoff
- **Visual Effects**: Earth curvature, atmospheric glow, space-to-sky gradient
- **Route Visibility**: Progressive highlighting during descent approach
- **Error Handling**: Robust fallback frames ensure generation continues
- **Variable Safety**: Protected against undefined position markers
### Enhanced Aerial Perspective
- **Optimal Height Range**: 1000-3000 meters for perfect aerial views

View File

@@ -1,6 +1,6 @@
"""
3D Video Animation Generator
Creates Relive-style 3D video animations from GPS route data
Creates professional Google Earth-style 3D video animations from GPS route data
"""
import json
@@ -9,10 +9,11 @@ import math
import requests
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import tempfile
import shutil
from datetime import datetime
import random
def generate_3d_video_animation(project_name, resources_folder, label_widget, progress_widget, popup_widget, clock_module):
"""
@@ -144,6 +145,7 @@ def generate_3d_video_animation(project_name, resources_folder, label_widget, pr
progress = 30 + (i / total_frames) * 40
update_progress(progress, f"Space entry frame {i+1}/{entry_frames}...")
try:
frame = create_space_entry_frame(
positions[0], center_lat, center_lon,
min_lat, max_lat, min_lon, max_lon,
@@ -154,11 +156,21 @@ def generate_3d_video_animation(project_name, resources_folder, label_widget, pr
cv2.imwrite(frame_path, frame)
frame_counter += 1
except Exception as e:
print(f"Error generating space entry frame {i}: {e}")
# Create a simple fallback frame
fallback_frame = np.zeros((height, width, 3), dtype=np.uint8)
fallback_frame[:] = (0, 0, 50) # Space-like background
frame_path = os.path.join(frames_dir, f"frame_{frame_counter:06d}.png")
cv2.imwrite(frame_path, fallback_frame)
frame_counter += 1
# Generate route following frames
for i, pos in enumerate(positions):
progress = 30 + ((entry_frames + i) / total_frames) * 40
update_progress(progress, f"Route frame {i+1}/{len(positions)}...")
try:
frame = create_3d_frame(
pos, positions, i, center_lat, center_lon,
min_lat, max_lat, min_lon, max_lon,
@@ -170,6 +182,29 @@ def generate_3d_video_animation(project_name, resources_folder, label_widget, pr
cv2.imwrite(frame_path, frame)
frame_counter += 1
except Exception as e:
print(f"Error generating route frame {i}: {e}")
# Create a simple fallback frame to continue generation
fallback_frame = np.zeros((height, width, 3), dtype=np.uint8)
fallback_frame[:] = (50, 50, 100) # Dark blue background
frame_path = os.path.join(frames_dir, f"frame_{frame_counter:06d}.png")
cv2.imwrite(frame_path, fallback_frame)
frame_counter += 1
# Add transition bridge frame (smooth transition from space to route)
try:
update_progress(progress, "Creating transition bridge...")
transition_frame = create_transition_bridge_frame(
positions[0], center_lat, center_lon,
min_lat, max_lat, min_lon, max_lon,
width, height
)
frame_path = os.path.join(frames_dir, f"frame_{frame_counter:06d}.png")
cv2.imwrite(frame_path, transition_frame)
frame_counter += 1
except Exception as e:
print(f"Warning: Could not create transition bridge frame: {e}")
# Step 4: Create video
update_progress(75, "Compiling video...")
@@ -252,7 +287,10 @@ def create_3d_frame(current_pos, all_positions, frame_index, center_lat, center_
)
if is_visible:
route_points_3d.append((screen_x, screen_y, i <= frame_index))
# Mark points as past, current, or future
# Ensure at least the current position (frame_index) is marked as past
is_past_or_current = i <= frame_index
route_points_3d.append((screen_x, screen_y, is_past_or_current))
# Draw route with enhanced 3D effects
draw_3d_route(frame, route_points_3d, frame_index)
@@ -281,35 +319,144 @@ def calculate_bearing(lat1, lon1, lat2, lon2):
return bearing
def create_terrain_background(frame, width, height, camera_lat, camera_lon, bearing, tilt_angle):
"""Create a Google Earth-style terrain background"""
# Sky gradient (more realistic)
for y in range(int(height * 0.4)): # Sky takes upper 40%
sky_intensity = y / (height * 0.4)
# Sky colors: horizon (light blue) to zenith (darker blue)
r = int(135 + (200 - 135) * sky_intensity)
g = int(206 + (230 - 206) * sky_intensity)
b = int(235 + (255 - 235) * sky_intensity)
"""Create a professional Google Earth-style terrain background"""
# Enhanced sky gradient with realistic atmospheric scattering
for y in range(int(height * 0.35)): # Sky takes upper 35%
sky_intensity = y / (height * 0.35)
# Realistic sky colors with atmospheric perspective
horizon_r, horizon_g, horizon_b = 255, 248, 220 # Warm horizon
zenith_r, zenith_g, zenith_b = 135, 206, 235 # Sky blue
r = int(horizon_r + (zenith_r - horizon_r) * sky_intensity)
g = int(horizon_g + (zenith_g - horizon_g) * sky_intensity)
b = int(horizon_b + (zenith_b - horizon_b) * sky_intensity)
frame[y, :] = (b, g, r) # BGR format for OpenCV
# Terrain/ground gradient
terrain_start_y = int(height * 0.4)
for y in range(terrain_start_y, height):
# Create depth illusion
distance_factor = (y - terrain_start_y) / (height - terrain_start_y)
# Realistic terrain with multiple layers and textures
terrain_start_y = int(height * 0.35)
create_enhanced_terrain_layer(frame, width, height, terrain_start_y, camera_lat, camera_lon)
# Terrain colors: greens and browns
base_r = int(80 + 60 * distance_factor)
base_g = int(120 + 80 * distance_factor)
base_b = int(60 + 40 * distance_factor)
# Add atmospheric haze for depth
add_atmospheric_haze(frame, width, height, terrain_start_y)
# Add realistic cloud shadows
add_cloud_shadows(frame, width, height, terrain_start_y)
def create_enhanced_terrain_layer(frame, width, height, start_y, camera_lat, camera_lon):
"""Create enhanced terrain with realistic colors and textures"""
for y in range(start_y, height):
distance_factor = (y - start_y) / (height - start_y)
# Add terrain texture using noise
for x in range(width):
noise = (math.sin(x * 0.01 + y * 0.01) + math.sin(x * 0.05 + y * 0.02)) * 10
terrain_r = max(0, min(255, base_r + int(noise)))
terrain_g = max(0, min(255, base_g + int(noise)))
terrain_b = max(0, min(255, base_b + int(noise)))
# Multiple noise layers for realistic terrain variation
terrain_color = generate_enhanced_terrain_color(x, y, camera_lat, camera_lon, width, height, distance_factor)
frame[y, x] = terrain_color
frame[y, x] = (terrain_b, terrain_g, terrain_r)
def generate_enhanced_terrain_color(x, y, camera_lat, camera_lon, width, height, distance_factor):
"""Generate enhanced terrain color with realistic geographic features"""
# Base terrain using multiple octaves of noise
noise_scale1 = 0.01
noise_scale2 = 0.005
noise_scale3 = 0.002
# Primary terrain features
terrain1 = math.sin(x * noise_scale1) * math.sin(y * noise_scale1)
terrain2 = math.sin(x * noise_scale2 + 100) * math.sin(y * noise_scale2 + 100) * 0.7
terrain3 = math.sin(x * noise_scale3 + 200) * math.sin(y * noise_scale3 + 200) * 0.3
combined_terrain = terrain1 + terrain2 + terrain3
# Simulate geographic coordinate influence
lat_influence = math.sin(camera_lat * 0.1) * 0.5
lon_influence = math.cos(camera_lon * 0.1) * 0.3
geographic_factor = lat_influence + lon_influence
final_terrain = combined_terrain + geographic_factor
# Classify terrain types based on noise
if final_terrain > 1.2:
# High mountains - snow-capped peaks
base_color = (240, 248, 255) # Alice blue
elif final_terrain > 0.8:
# Mountains - rocky gray/brown
base_color = (105, 105, 105) # Dim gray
elif final_terrain > 0.4:
# Hills - forest green
base_color = (34, 139, 34) # Forest green
elif final_terrain > 0.1:
# Plains - grassland
base_color = (124, 252, 0) # Lawn green
elif final_terrain > -0.2:
# Agricultural areas - golden
base_color = (255, 215, 0) # Gold
elif final_terrain > -0.5:
# Desert/arid - sandy brown
base_color = (244, 164, 96) # Sandy brown
else:
# Water bodies - deep blue
base_color = (25, 25, 112) # Midnight blue
# Apply distance-based atmospheric perspective
atmosphere_fade = 1.0 - (distance_factor * 0.4)
final_color = tuple(int(c * atmosphere_fade + 200 * (1 - atmosphere_fade)) for c in base_color)
# Add subtle texture variation
texture_noise = (math.sin(x * 0.1) * math.sin(y * 0.1)) * 10
final_color = tuple(max(0, min(255, c + int(texture_noise))) for c in final_color)
return final_color
def add_atmospheric_haze(frame, width, height, terrain_start_y):
"""Add realistic atmospheric haze for depth perception"""
haze_overlay = np.zeros_like(frame)
for y in range(terrain_start_y, height):
distance_factor = (y - terrain_start_y) / (height - terrain_start_y)
haze_intensity = distance_factor * 0.3 # Stronger haze in distance
if haze_intensity > 0:
haze_color = int(220 * haze_intensity) # Light blue-gray haze
haze_overlay[y, :] = (haze_color, haze_color, haze_color)
# Blend haze with terrain
cv2.addWeighted(frame, 1.0, haze_overlay, 0.3, 0, frame)
def add_cloud_shadows(frame, width, height, terrain_start_y):
"""Add realistic cloud shadows on terrain"""
shadow_overlay = np.zeros_like(frame)
# Generate cloud shadow patterns
for shadow_id in range(3):
shadow_center_x = int(width * (0.2 + shadow_id * 0.3))
shadow_center_y = int(terrain_start_y + (height - terrain_start_y) * 0.3)
shadow_radius = 80 + shadow_id * 30
# Create soft circular shadows
for y in range(max(terrain_start_y, shadow_center_y - shadow_radius),
min(height, shadow_center_y + shadow_radius)):
for x in range(max(0, shadow_center_x - shadow_radius),
min(width, shadow_center_x + shadow_radius)):
distance = math.sqrt((x - shadow_center_x)**2 + (y - shadow_center_y)**2)
if distance < shadow_radius:
shadow_intensity = 1.0 - (distance / shadow_radius)
shadow_intensity *= 0.3 # Subtle shadows
shadow_value = int(50 * shadow_intensity)
shadow_overlay[y, x] = (shadow_value, shadow_value, shadow_value)
# Apply shadows
frame_dark = frame.astype(np.int32) - shadow_overlay.astype(np.int32)
frame[:] = np.clip(frame_dark, 0, 255).astype(np.uint8)
def calculate_visible_bounds(camera_lat, camera_lon, bearing, view_distance, width, height):
"""Calculate the bounds of the visible area"""
@@ -400,10 +547,20 @@ def draw_3d_route(frame, route_points_3d, current_frame_index):
# Draw current position marker
if route_points_3d:
# Find the current position - look for the last "past" point, or use the first point
current_x, current_y = None, None
# Try to find the last past point
for x, y, is_past in route_points_3d:
if is_past:
current_x, current_y = x, y
# If no past points found (beginning of route), use the first point
if current_x is None and len(route_points_3d) > 0:
current_x, current_y, _ = route_points_3d[0]
# Only draw marker if we have a valid position
if current_x is not None and current_y is not None:
# Pulsing current position marker
pulse_size = int(12 + 8 * math.sin(current_frame_index * 0.3))
@@ -662,63 +819,222 @@ def get_enhanced_elevation(lat, lon, point_index, frame_index):
def create_space_entry_frame(start_pos, center_lat, center_lon, min_lat, max_lat, min_lon, max_lon,
width, height, frame_index, total_entry_frames):
"""
Create a Google Earth-style space entry frame transitioning from space to route start
Create a realistic Google Earth-style space entry frame
"""
# Create canvas
# Create high-resolution canvas
frame = np.zeros((height, width, 3), dtype=np.uint8)
# Calculate entry progress (0 to 1)
entry_progress = frame_index / total_entry_frames
# Space entry parameters - start very high and descend
max_altitude = 50000 # Start from 50km altitude (space view)
min_altitude = 2000 # End at 2km altitude (good aerial view)
# Realistic altitude progression
max_altitude = 50000 # 50km - edge of space
min_altitude = 2000 # 2km - final descent altitude
# Smooth descent curve (ease-out animation)
altitude_progress = 1 - (1 - entry_progress) ** 3 # Cubic ease-out
# Smooth descent with realistic deceleration
altitude_progress = 1 - (1 - entry_progress) ** 2.5
current_altitude = max_altitude - (max_altitude - min_altitude) * altitude_progress
# Camera position starts centered over the route
camera_lat = center_lat
camera_lon = center_lon
# Create realistic Earth background
create_realistic_earth_background(frame, width, height, current_altitude, center_lat, center_lon, entry_progress)
# Camera gradually moves toward route start
start_lat = start_pos['latitude']
start_lon = start_pos['longitude']
# Add realistic cloud layers
add_realistic_cloud_layers(frame, width, height, current_altitude, entry_progress)
# Smooth transition to route start position
transition_progress = entry_progress ** 2 # Quadratic for gradual transition
camera_lat = center_lat + (start_lat - center_lat) * transition_progress
camera_lon = center_lon + (start_lon - center_lon) * transition_progress
# Draw geographic features (landmasses, coastlines, rivers)
draw_geographic_features(frame, width, height, center_lat, center_lon, current_altitude, entry_progress)
# Create space/sky background based on altitude
create_space_sky_background(frame, width, height, current_altitude)
# Calculate view bounds based on altitude
view_radius_km = current_altitude * 0.8 # View radius increases with altitude
# Draw Earth curvature effect at high altitudes
if current_altitude > 10000:
draw_earth_curvature(frame, width, height, current_altitude)
# Draw terrain with increasing detail as we descend
draw_terrain_from_altitude(frame, camera_lat, camera_lon, view_radius_km,
# Add route visualization that becomes more detailed as we descend
if entry_progress > 0.4: # Route becomes visible halfway through descent
draw_route_from_space(frame, min_lat, max_lat, min_lon, max_lon, center_lat, center_lon,
width, height, current_altitude, entry_progress)
# Draw route overview (visible from space)
if entry_progress > 0.3: # Route becomes visible partway through descent
draw_route_overview_from_space(frame, min_lat, max_lat, min_lon, max_lon,
camera_lat, camera_lon, view_radius_km,
width, height, entry_progress)
# Add realistic atmospheric effects
add_space_atmospheric_effects(frame, width, height, current_altitude, entry_progress)
# Add space entry UI
add_space_entry_ui(frame, current_altitude, entry_progress, width, height)
# Add professional UI with realistic information
add_space_entry_professional_ui(frame, current_altitude, entry_progress, start_pos, width, height)
# Add atmospheric glow effect
add_atmospheric_glow(frame, width, height, current_altitude)
# Add Earth's terminator line (day/night boundary) if at high altitude
if current_altitude > 20000:
add_earth_terminator(frame, width, height, current_altitude)
return frame
def create_realistic_earth_background(frame, width, height, altitude, center_lat, center_lon, progress):
"""Create realistic Earth background based on altitude"""
if altitude > 30000: # Space view - show Earth as sphere
create_earth_sphere_view(frame, width, height, altitude, center_lat, center_lon)
elif altitude > 15000: # High atmosphere - curved horizon
create_curved_horizon_view(frame, width, height, altitude, center_lat, center_lon)
else: # Lower atmosphere - flat perspective
create_flat_earth_view(frame, width, height, altitude, center_lat, center_lon, progress)
def create_earth_sphere_view(frame, width, height, altitude, center_lat, center_lon):
"""Create spherical Earth view for space altitudes"""
# Space background - deep black with stars
frame[:] = (5, 5, 15) # Very dark blue-black
# Add stars
np.random.seed(42) # Consistent star pattern
for _ in range(200):
x = np.random.randint(0, width)
y = np.random.randint(0, height // 2) # Stars only in upper half
brightness = np.random.randint(100, 255)
frame[y, x] = (brightness, brightness, brightness)
# Earth sphere
earth_radius = min(width, height) // 3
earth_center_x = width // 2
earth_center_y = int(height * 0.7) # Earth in lower portion
# Create Earth disk
y_coords, x_coords = np.ogrid[:height, :width]
earth_mask = (x_coords - earth_center_x)**2 + (y_coords - earth_center_y)**2 <= earth_radius**2
# Earth base colors (blue oceans, green/brown land)
earth_colors = create_earth_surface_colors(width, height, earth_center_x, earth_center_y, earth_radius)
frame[earth_mask] = earth_colors[earth_mask]
# Add Earth's atmospheric glow
add_earth_atmospheric_glow(frame, earth_center_x, earth_center_y, earth_radius, width, height)
def create_curved_horizon_view(frame, width, height, altitude, center_lat, center_lon):
"""Create curved horizon view for high atmosphere"""
# Sky gradient from space to atmosphere
for y in range(height):
if y < height * 0.3: # Upper atmosphere/space
intensity = y / (height * 0.3)
r = int(5 + (50 - 5) * intensity)
g = int(10 + (80 - 10) * intensity)
b = int(25 + (120 - 25) * intensity)
else: # Lower atmosphere
intensity = (y - height * 0.3) / (height * 0.7)
r = int(50 + (135 - 50) * intensity)
g = int(80 + (206 - 80) * intensity)
b = int(120 + (235 - 120) * intensity)
frame[y, :] = (b, g, r)
# Curved horizon line
horizon_y = int(height * 0.6)
curvature = altitude / 1000 # More curvature at higher altitude
for x in range(width):
curve_offset = int(curvature * math.sin(math.pi * x / width))
curve_y = horizon_y + curve_offset
# Earth surface below horizon
if curve_y < height:
earth_surface_color = get_earth_surface_color(x, curve_y, center_lat, center_lon, width, height)
for y in range(curve_y, height):
if y < height:
frame[y, x] = earth_surface_color
def create_flat_earth_view(frame, width, height, altitude, center_lat, center_lon, progress):
"""Create flat Earth perspective for lower altitudes"""
# Realistic sky gradient
for y in range(int(height * 0.4)):
sky_intensity = y / (height * 0.4)
r = int(135 + (200 - 135) * sky_intensity)
g = int(206 + (230 - 206) * sky_intensity)
b = int(235 + (255 - 235) * sky_intensity)
frame[y, :] = (b, g, r)
# Terrain with realistic colors and textures
terrain_start_y = int(height * 0.4)
for y in range(terrain_start_y, height):
for x in range(width):
terrain_color = generate_realistic_terrain_color(x, y, center_lat, center_lon, width, height, altitude)
frame[y, x] = terrain_color
def add_realistic_cloud_layers(frame, width, height, altitude, progress):
"""Add realistic cloud formations"""
if altitude < 30000: # Clouds visible below 30km
cloud_density = max(0.1, 1.0 - altitude / 30000)
# Generate cloud layer using Perlin-like noise
for y in range(int(height * 0.3), int(height * 0.7)):
for x in range(0, width, 4): # Sample every 4 pixels for performance
cloud_noise = (
math.sin(x * 0.02 + progress * 10) *
math.sin(y * 0.03 + progress * 8) *
math.sin((x + y) * 0.01 + progress * 5)
)
cloud_intensity = max(0, cloud_noise * cloud_density)
if cloud_intensity > 0.3:
cloud_alpha = min(0.6, cloud_intensity)
cloud_color = (255, 255, 255)
# Blend cloud with existing background
for dx in range(4):
if x + dx < width:
current_color = frame[y, x + dx]
blended = [
int(current_color[i] * (1 - cloud_alpha) + cloud_color[i] * cloud_alpha)
for i in range(3)
]
frame[y, x + dx] = tuple(blended)
def draw_geographic_features(frame, width, height, center_lat, center_lon, altitude, progress):
"""Draw realistic geographic features like coastlines and rivers"""
if altitude < 20000: # Geographic features visible below 20km
detail_level = 1.0 - (altitude / 20000)
# Simulate coastlines using fractal-like patterns
coastline_points = generate_coastline_pattern(center_lat, center_lon, width, height, detail_level)
for points in coastline_points:
if len(points) > 1:
# Draw coastline
for i in range(len(points) - 1):
cv2.line(frame, points[i], points[i + 1], (139, 69, 19), 2) # Brown coastline
# Add major rivers if detail level is high enough
if detail_level > 0.5:
river_points = generate_river_pattern(center_lat, center_lon, width, height, detail_level)
for points in river_points:
if len(points) > 1:
for i in range(len(points) - 1):
cv2.line(frame, points[i], points[i + 1], (255, 178, 102), 1) # Blue rivers
def create_earth_surface_colors(width, height, center_x, center_y, radius):
"""Generate realistic Earth surface colors"""
colors = np.zeros((height, width, 3), dtype=np.uint8)
for y in range(height):
for x in range(width):
dist_from_center = math.sqrt((x - center_x)**2 + (y - center_y)**2)
if dist_from_center <= radius:
# Use longitude/latitude to determine terrain type
angle = math.atan2(y - center_y, x - center_x)
# Simulate different terrain types
terrain_noise = (
math.sin(angle * 3) *
math.sin(dist_from_center * 0.1) *
math.cos(angle * 2 + dist_from_center * 0.05)
)
if terrain_noise > 0.3:
# Land - green/brown
colors[y, x] = (34, 139, 34) # Forest green
elif terrain_noise > 0:
# Land - brown/tan
colors[y, x] = (160, 82, 45) # Saddle brown
else:
# Ocean - blue
colors[y, x] = (139, 0, 0) # Dark blue
return colors
def create_space_sky_background(frame, width, height, altitude):
"""Create background that transitions from space black to sky blue"""
# Space to atmosphere transition
@@ -770,10 +1086,16 @@ def draw_earth_curvature(frame, width, height, altitude):
for glow_y in range(max(0, curve_y - 20), min(height, curve_y + 5)):
glow_intensity = 1.0 - abs(glow_y - curve_y) / 20.0
if glow_intensity > 0:
# Use numpy operations to prevent overflow
current_pixel = frame[glow_y, x].astype(np.int32) # Convert to int32 to prevent overflow
glow_r = int(100 * glow_intensity)
glow_g = int(150 * glow_intensity)
glow_b = int(200 * glow_intensity)
frame[glow_y, x] = (
min(255, frame[glow_y, x][0] + int(100 * glow_intensity)),
min(255, frame[glow_y, x][1] + int(150 * glow_intensity)),
min(255, frame[glow_y, x][2] + int(200 * glow_intensity))
min(255, max(0, current_pixel[0] + glow_r)),
min(255, max(0, current_pixel[1] + glow_g)),
min(255, max(0, current_pixel[2] + glow_b))
)
def draw_terrain_from_altitude(frame, camera_lat, camera_lon, view_radius_km,
@@ -888,4 +1210,418 @@ def add_atmospheric_glow(frame, width, height, altitude):
distance_from_horizon = abs(y - height // 2) / (height // 2)
if distance_from_horizon < 0.5:
glow = int(50 * glow_intensity * (1 - distance_from_horizon * 2))
frame[y, :, 2] = np.minimum(255, frame[y, :, 2] + glow) # Add blue glow
# Use numpy operations to safely add glow without overflow
current_blue = frame[y, :, 2].astype(np.int32)
frame[y, :, 2] = np.clip(current_blue + glow, 0, 255).astype(np.uint8)
def ensure_safe_pixel_value(value):
"""Ensure pixel values are within valid range (0-255)"""
return max(0, min(255, int(value)))
def safe_frame_assignment(frame, y, x, color):
"""Safely assign color values to frame to prevent overflow"""
if isinstance(color, (list, tuple)) and len(color) == 3:
frame[y, x] = (
ensure_safe_pixel_value(color[0]),
ensure_safe_pixel_value(color[1]),
ensure_safe_pixel_value(color[2])
)
else:
# Single value color
safe_value = ensure_safe_pixel_value(color)
frame[y, x] = (safe_value, safe_value, safe_value)
def create_transition_bridge_frame(start_pos, center_lat, center_lon, min_lat, max_lat, min_lon, max_lon,
width, height):
"""
Create a smooth transition frame that bridges space entry to route following
"""
# This is essentially the first route frame but with a slightly higher camera position
# to create a smooth transition from the space entry descent
# Create canvas
frame = np.zeros((height, width, 3), dtype=np.uint8)
# Transition camera parameters (between space entry end and route start)
camera_height = 2500 # Slightly higher than normal route following
camera_lat = start_pos['latitude']
camera_lon = start_pos['longitude']
# Create sky background (transition from space-like to normal sky)
for y in range(int(height * 0.5)): # Sky portion
sky_intensity = y / (height * 0.5)
r = int(100 + (200 - 100) * sky_intensity)
g = int(150 + (230 - 150) * sky_intensity)
b = int(200 + (255 - 200) * sky_intensity)
frame[y, :] = (b, g, r)
# Terrain background
terrain_start_y = int(height * 0.5)
for y in range(terrain_start_y, height):
distance_factor = (y - terrain_start_y) / (height - terrain_start_y)
base_r = int(80 + 60 * distance_factor)
base_g = int(120 + 80 * distance_factor)
base_b = int(60 + 40 * distance_factor)
frame[y, :] = (base_b, base_g, base_r)
# Add route start indicator
route_center_x = width // 2
route_center_y = int(height * 0.7)
# Draw route start marker
cv2.circle(frame, (route_center_x, route_center_y), 20, (0, 255, 255), 3)
cv2.circle(frame, (route_center_x, route_center_y), 8, (255, 255, 255), -1)
# Add "Route Starting" text
cv2.putText(frame, "Route Starting...", (width//2 - 100, height//2 + 100),
cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 2)
return frame
def get_earth_surface_color(x, y, center_lat, center_lon, width, height):
"""Get realistic Earth surface color for a given screen position"""
# Convert screen position to geographic simulation
terrain_noise = (
math.sin(x * 0.01) * math.sin(y * 0.01) +
math.sin(x * 0.05) * math.sin(y * 0.03) +
math.sin(x * 0.02 + y * 0.02)
)
if terrain_noise > 0.5:
# Mountains/hills - brown/gray
return (101, 67, 33)
elif terrain_noise > 0:
# Plains/grassland - green
return (34, 139, 34)
elif terrain_noise > -0.3:
# Desert/dry land - tan
return (194, 178, 128)
else:
# Water - blue
return (65, 105, 225)
def generate_realistic_terrain_color(x, y, center_lat, center_lon, width, height, altitude):
"""Generate realistic terrain color with proper texturing"""
# Multiple noise layers for realistic terrain
noise1 = math.sin(x * 0.005) * math.sin(y * 0.005)
noise2 = math.sin(x * 0.02) * math.sin(y * 0.02) * 0.5
noise3 = math.sin(x * 0.1) * math.sin(y * 0.1) * 0.2
combined_noise = noise1 + noise2 + noise3
# Distance from center affects terrain type
center_x, center_y = width // 2, height // 2
distance_from_center = math.sqrt((x - center_x)**2 + (y - center_y)**2) / min(width, height)
# Terrain classification based on noise and position
if combined_noise > 0.7:
# High mountains - gray/white
base_color = (169, 169, 169)
elif combined_noise > 0.3:
# Hills/forests - green
base_color = (34, 139, 34)
elif combined_noise > 0:
# Plains - light green
base_color = (124, 252, 0)
elif combined_noise > -0.3:
# Desert/dry areas - tan
base_color = (210, 180, 140)
else:
# Water/wetlands - blue
base_color = (65, 105, 225)
# Add altitude-based atmospheric perspective
distance_factor = min(1.0, (y - height * 0.4) / (height * 0.6))
atmosphere_factor = 1.0 - (distance_factor * 0.3)
final_color = tuple(int(c * atmosphere_factor) for c in base_color)
return final_color
def generate_coastline_pattern(center_lat, center_lon, width, height, detail_level):
"""Generate realistic coastline patterns"""
coastlines = []
if detail_level > 0.3:
# Generate several coastline segments
for coast_id in range(3):
points = []
start_x = int(width * (0.1 + coast_id * 0.3))
start_y = int(height * 0.6)
# Generate fractal-like coastline
for i in range(20):
noise_x = int(20 * math.sin(i * 0.5 + coast_id) * detail_level)
noise_y = int(10 * math.cos(i * 0.3 + coast_id) * detail_level)
x = start_x + i * 30 + noise_x
y = start_y + noise_y
if 0 <= x < width and 0 <= y < height:
points.append((x, y))
if len(points) > 1:
coastlines.append(points)
return coastlines
def generate_river_pattern(center_lat, center_lon, width, height, detail_level):
"""Generate realistic river patterns"""
rivers = []
if detail_level > 0.6:
# Generate a few major rivers
for river_id in range(2):
points = []
start_x = int(width * (0.2 + river_id * 0.6))
start_y = int(height * 0.3)
# Rivers flow generally downward with meanders
for i in range(15):
meander = int(15 * math.sin(i * 0.8 + river_id * 2))
x = start_x + meander
y = start_y + i * 25
if 0 <= x < width and 0 <= y < height:
points.append((x, y))
if len(points) > 1:
rivers.append(points)
return rivers
def add_earth_atmospheric_glow(frame, center_x, center_y, radius, width, height):
"""Add realistic atmospheric glow around Earth"""
for y in range(max(0, center_y - radius - 50), min(height, center_y + radius + 50)):
for x in range(max(0, center_x - radius - 50), min(width, center_x + radius + 50)):
distance = math.sqrt((x - center_x)**2 + (y - center_y)**2)
if radius < distance < radius + 40:
# Atmospheric glow
glow_intensity = 1.0 - (distance - radius) / 40.0
if glow_intensity > 0:
glow_blue = int(100 * glow_intensity)
current_color = frame[y, x].astype(np.int32)
frame[y, x] = (
np.clip(current_color[0] + glow_blue // 3, 0, 255),
np.clip(current_color[1] + glow_blue // 2, 0, 255),
np.clip(current_color[2] + glow_blue, 0, 255)
)
def draw_route_from_space(frame, min_lat, max_lat, min_lon, max_lon, camera_lat, camera_lon,
width, height, altitude, progress):
"""Draw route visualization visible from space with realistic styling"""
# Calculate route bounds on screen
lat_center = (min_lat + max_lat) / 2
lon_center = (min_lon + max_lon) / 2
# Project to screen coordinates
lat_offset = (lat_center - camera_lat) * 100000 / altitude
lon_offset = (lon_center - camera_lon) * 100000 / altitude
route_x = int(width / 2 + lon_offset)
route_y = int(height / 2 + lat_offset)
if 0 < route_x < width and 0 < route_y < height:
# Route area highlight - pulsing effect
pulse = 1.0 + 0.3 * math.sin(progress * 20)
route_size = int(20 * pulse)
# Outer glow
cv2.circle(frame, (route_x, route_y), route_size + 10, (100, 100, 255), 2)
# Main route indicator
cv2.circle(frame, (route_x, route_y), route_size, (255, 255, 100), 3)
# Inner core
cv2.circle(frame, (route_x, route_y), route_size // 2, (255, 255, 255), -1)
# Route path preview (simplified)
route_length = int(40 + progress * 60)
for i in range(5):
angle = i * math.pi / 2
end_x = route_x + int(route_length * math.cos(angle))
end_y = route_y + int(route_length * math.sin(angle))
cv2.line(frame, (route_x, route_y), (end_x, end_y), (255, 200, 100), 2)
def add_space_atmospheric_effects(frame, width, height, altitude, progress):
"""Add realistic atmospheric effects based on altitude"""
if altitude > 25000:
# Space effects - stars and cosmic background
add_star_field(frame, width, height, altitude)
if 5000 < altitude < 30000:
# Atmospheric scattering effects
add_atmospheric_scattering(frame, width, height, altitude)
# Earth's limb glow at high altitudes
if altitude > 15000:
add_earth_limb_glow(frame, width, height, altitude)
def add_star_field(frame, width, height, altitude):
"""Add realistic star field for space views"""
star_intensity = min(1.0, (altitude - 25000) / 25000)
num_stars = int(300 * star_intensity)
np.random.seed(42) # Consistent star pattern
for _ in range(num_stars):
x = np.random.randint(0, width)
y = np.random.randint(0, height // 2) # Stars mainly in upper half
# Vary star brightness and size
brightness = np.random.randint(150, 255)
size = np.random.choice([1, 1, 1, 2], p=[0.7, 0.2, 0.05, 0.05])
if size == 1:
frame[y, x] = (brightness, brightness, brightness)
else:
cv2.circle(frame, (x, y), size, (brightness, brightness, brightness), -1)
def add_atmospheric_scattering(frame, width, height, altitude):
"""Add atmospheric scattering effects"""
scattering_intensity = 1.0 - (altitude / 30000)
# Blue scattering in upper atmosphere
for y in range(0, int(height * 0.5)):
scatter_factor = scattering_intensity * (1.0 - y / (height * 0.5))
blue_scatter = int(20 * scatter_factor)
for x in range(0, width, 4): # Sample for performance
current_color = frame[y, x:x+4]
frame[y, x:x+4] = np.minimum(255, current_color + [blue_scatter//2, blue_scatter//2, blue_scatter])
def add_earth_limb_glow(frame, width, height, altitude):
"""Add Earth's limb glow effect"""
limb_intensity = min(1.0, (altitude - 15000) / 20000)
# Horizontal glow band representing Earth's atmosphere
glow_y = int(height * 0.7)
glow_height = int(30 * limb_intensity)
for y in range(max(0, glow_y - glow_height), min(height, glow_y + glow_height)):
glow_factor = 1.0 - abs(y - glow_y) / glow_height
blue_glow = int(80 * glow_factor * limb_intensity)
frame[y, :, 2] = np.minimum(255, frame[y, :, 2] + blue_glow)
def add_earth_terminator(frame, width, height, altitude):
"""Add Earth's day/night terminator line"""
if altitude > 20000:
# Diagonal terminator line
terminator_angle = math.pi / 6 # 30 degrees
for y in range(height):
terminator_x = int(width * 0.3 + y * math.tan(terminator_angle))
if 0 < terminator_x < width:
# Darken the night side
for x in range(0, terminator_x):
current_color = frame[y, x].astype(np.int32)
darkened = current_color * 0.3 # 70% darker
frame[y, x] = np.clip(darkened, 0, 255).astype(np.uint8)
# Add terminator glow
glow_width = 20
for dx in range(-glow_width, glow_width):
glow_x = terminator_x + dx
if 0 <= glow_x < width:
glow_intensity = 1.0 - abs(dx) / glow_width
orange_glow = int(50 * glow_intensity)
current_color = frame[y, glow_x].astype(np.int32)
frame[y, glow_x] = np.clip(current_color + [orange_glow//2, orange_glow//2, orange_glow], 0, 255)
def add_space_entry_professional_ui(frame, altitude, progress, start_pos, width, height):
"""Add professional Google Earth-style UI for space entry"""
# Create semi-transparent overlay panels
overlay = frame.copy()
# Main information panel (top-left)
panel_width = 320
panel_height = 140
cv2.rectangle(overlay, (20, 20), (panel_width, panel_height), (40, 40, 40), -1)
cv2.addWeighted(overlay, 0.8, frame, 0.2, 0, frame)
# Panel border with gradient effect
cv2.rectangle(frame, (20, 20), (panel_width, panel_height), (200, 200, 200), 2)
cv2.rectangle(frame, (22, 22), (panel_width-2, panel_height-2), (100, 100, 100), 1)
# Altitude display (large, prominent)
altitude_text = f"{altitude/1000:.1f} km"
cv2.putText(frame, "ALTITUDE", (30, 45), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (150, 150, 150), 1)
cv2.putText(frame, altitude_text, (30, 75), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 255), 2)
# Descent progress
progress_text = f"DESCENT: {progress*100:.0f}%"
cv2.putText(frame, progress_text, (30, 105), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (100, 255, 100), 2)
# Coordinates
coord_text = f"LAT: {start_pos['latitude']:.4f}"
cv2.putText(frame, coord_text, (30, 125), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (200, 200, 200), 1)
coord_text = f"LON: {start_pos['longitude']:.4f}"
cv2.putText(frame, coord_text, (30, 145), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (200, 200, 200), 1)
# Speed indicator (top-right)
speed_panel_x = width - 250
cv2.rectangle(overlay, (speed_panel_x, 20), (width - 20, 100), (40, 40, 40), -1)
cv2.addWeighted(overlay, 0.8, frame, 0.2, 0, frame)
cv2.rectangle(frame, (speed_panel_x, 20), (width - 20, 100), (200, 200, 200), 2)
descent_speed = int((1 - progress) * 15000 + 500) # Simulated descent speed
cv2.putText(frame, "DESCENT RATE", (speed_panel_x + 10, 45), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (150, 150, 150), 1)
cv2.putText(frame, f"{descent_speed} m/min", (speed_panel_x + 10, 75), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 100, 100), 2)
# Entry status message (center)
if progress < 0.3:
status_text = "INITIATING DESCENT FROM SPACE"
text_color = (100, 200, 255)
elif progress < 0.7:
status_text = "ENTERING EARTH'S ATMOSPHERE"
text_color = (255, 200, 100)
else:
status_text = "APPROACHING ROUTE START POINT"
text_color = (100, 255, 100)
text_size = cv2.getTextSize(status_text, cv2.FONT_HERSHEY_SIMPLEX, 0.8, 2)[0]
text_x = (width - text_size[0]) // 2
text_y = height - 80
# Text background
cv2.rectangle(frame, (text_x - 10, text_y - 35), (text_x + text_size[0] + 10, text_y + 10), (0, 0, 0), -1)
cv2.putText(frame, status_text, (text_x, text_y), cv2.FONT_HERSHEY_SIMPLEX, 0.8, text_color, 2)
# Progress bar (bottom)
progress_bar_width = width - 100
progress_bar_height = 8
progress_bar_x = 50
progress_bar_y = height - 40
# Background
cv2.rectangle(frame, (progress_bar_x, progress_bar_y),
(progress_bar_x + progress_bar_width, progress_bar_y + progress_bar_height),
(60, 60, 60), -1)
# Progress fill with color gradient
progress_width = int(progress_bar_width * progress)
if progress_width > 0:
# Create gradient effect
for x in range(progress_width):
color_factor = x / progress_width if progress_width > 0 else 0
r = int(255 * (1 - color_factor) + 100 * color_factor)
g = int(100 * (1 - color_factor) + 255 * color_factor)
b = 100
cv2.rectangle(frame, (progress_bar_x + x, progress_bar_y),
(progress_bar_x + x + 1, progress_bar_y + progress_bar_height),
(b, g, r), -1)
# Border
cv2.rectangle(frame, (progress_bar_x, progress_bar_y),
(progress_bar_x + progress_bar_width, progress_bar_y + progress_bar_height),
(200, 200, 200), 1)

View File

@@ -1 +1 @@
gAAAAABobLgWZWKYF0nkSynV8d6s9J_G4GWuCbRofa_raK783ueF0ES9WXnIX02OcwMWWgpV1Ps4DJxDBTXtAQfjWHR0WrIN-FfcnViS1PEFFNDUtsN_PSSTND2vLOQEMRtUYYKG_UDZ
gAAAAABobPcZPB2ZDJEqHef1TANu1yOi8sYRts1-zpn_zcMBH3ydy0TWJp_G1YWt_G7dpvK29qN2UtnLkhi6-_EXq9AWcy1xHgF6FL5jl27RhdBF3-zNDSFOcDDnSVVbgvMjG88tOBMa

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 907 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 907 KiB

107
test_enhanced_video.py Normal file
View File

@@ -0,0 +1,107 @@
#!/usr/bin/env python3
"""
Test the enhanced Google Earth-style video generation
"""
import sys
import os
sys.path.append('/home/pi/Desktop/traccar_animation')
from py_scripts.video_3d_generator import create_space_entry_frame, create_3d_frame
import numpy as np
import cv2
def test_enhanced_visuals():
"""Test the enhanced Google Earth-style visuals"""
print("Testing enhanced Google Earth-style video generation...")
# Test parameters
start_pos = {
'latitude': 45.7749,
'longitude': -122.4194,
'speed': 0,
'deviceTime': '2025-07-08 12:00:00'
}
positions = [start_pos]
center_lat = 45.7749
center_lon = -122.4194
min_lat = 45.7700
max_lat = 45.7800
min_lon = -122.4250
max_lon = -122.4150
width = 1920
height = 1080
# Test space entry frames at different altitudes
test_frames = [0, 30, 60, 89] # Beginning, middle, end of space entry
for frame_idx in test_frames:
print(f"Testing space entry frame {frame_idx}/90...")
try:
frame = create_space_entry_frame(
start_pos, center_lat, center_lon,
min_lat, max_lat, min_lon, max_lon,
width, height, frame_idx, 90
)
# Verify frame quality
if frame is None:
print(f"❌ Frame {frame_idx} is None")
return False
if frame.shape != (height, width, 3):
print(f"❌ Frame {frame_idx} wrong shape: {frame.shape}")
return False
# Check for visual diversity (not just black/empty)
unique_colors = len(np.unique(frame.reshape(-1, frame.shape[2]), axis=0))
if unique_colors < 100: # Should have many colors for realistic visuals
print(f"❌ Frame {frame_idx} too few colors: {unique_colors}")
return False
print(f"✅ Space entry frame {frame_idx} - Colors: {unique_colors}, Range: {np.min(frame)}-{np.max(frame)}")
except Exception as e:
print(f"❌ Space entry frame {frame_idx} failed: {e}")
return False
# Test route following frame
print("Testing enhanced route following frame...")
try:
route_frame = create_3d_frame(
start_pos, positions, 0, center_lat, center_lon,
min_lat, max_lat, min_lon, max_lon, width, height
)
if route_frame is None:
print("❌ Route frame is None")
return False
unique_colors = len(np.unique(route_frame.reshape(-1, route_frame.shape[2]), axis=0))
if unique_colors < 100:
print(f"❌ Route frame too few colors: {unique_colors}")
return False
print(f"✅ Route frame - Colors: {unique_colors}, Range: {np.min(route_frame)}-{np.max(route_frame)}")
except Exception as e:
print(f"❌ Route frame failed: {e}")
return False
print("✅ All enhanced visual tests passed!")
print("🌍 Google Earth-style backgrounds are working properly")
print("🚀 Space entry sequence has realistic visuals")
print("🎬 High-quality terrain and atmospheric effects generated")
return True
if __name__ == "__main__":
success = test_enhanced_visuals()
if success:
print("\n🎉 Enhanced Google Earth-style video generation is ready!")
sys.exit(0)
else:
print("\n❌ Enhanced video generation test failed")
sys.exit(1)

115
test_transition.py Normal file
View File

@@ -0,0 +1,115 @@
#!/usr/bin/env python3
"""
Test script to verify the transition from space entry to route following works correctly
"""
import sys
import os
sys.path.append('/home/pi/Desktop/traccar_animation')
from py_scripts.video_3d_generator import create_3d_frame, draw_3d_route
import numpy as np
def test_route_transition():
"""Test the transition from space entry to route following"""
print("Testing route transition...")
# Sample route positions
positions = [
{'latitude': 45.7749, 'longitude': -122.4194, 'speed': 0, 'deviceTime': '2025-07-08 12:00:00'},
{'latitude': 45.7750, 'longitude': -122.4195, 'speed': 20, 'deviceTime': '2025-07-08 12:01:00'},
{'latitude': 45.7751, 'longitude': -122.4196, 'speed': 30, 'deviceTime': '2025-07-08 12:02:00'},
{'latitude': 45.7752, 'longitude': -122.4197, 'speed': 40, 'deviceTime': '2025-07-08 12:03:00'},
{'latitude': 45.7753, 'longitude': -122.4198, 'speed': 50, 'deviceTime': '2025-07-08 12:04:00'},
]
# Test parameters
center_lat = 45.7751
center_lon = -122.4196
min_lat = 45.7740
max_lat = 45.7760
min_lon = -122.4210
max_lon = -122.4180
width = 1920
height = 1080
# Test the first few frames (transition period)
for frame_index in range(len(positions)):
print(f"Testing route frame {frame_index}...")
try:
current_pos = positions[frame_index]
frame = create_3d_frame(
current_pos, positions, frame_index,
center_lat, center_lon, min_lat, max_lat, min_lon, max_lon,
width, height
)
# Check frame integrity
if frame is None:
print(f"ERROR: Route frame {frame_index} is None")
return False
if frame.shape != (height, width, 3):
print(f"ERROR: Route frame {frame_index} has wrong shape: {frame.shape}")
return False
# Check for valid pixel values
if np.any(frame < 0) or np.any(frame > 255):
print(f"ERROR: Route frame {frame_index} has invalid pixel values")
return False
print(f"Route frame {frame_index} OK - Shape: {frame.shape}, Min: {np.min(frame)}, Max: {np.max(frame)}")
except Exception as e:
print(f"ERROR: Route frame {frame_index} failed: {e}")
import traceback
traceback.print_exc()
return False
print("All route transition frames generated successfully!")
return True
def test_draw_3d_route():
"""Test the draw_3d_route function with various scenarios"""
print("Testing draw_3d_route function...")
# Create test frame
frame = np.zeros((1080, 1920, 3), dtype=np.uint8)
# Test scenarios
test_cases = [
# Empty route
([], 0, "Empty route"),
# Single point - no past points
([(960, 540, False)], 0, "Single future point"),
# Single point - current point
([(960, 540, True)], 0, "Single current point"),
# Multiple points - beginning of route
([(960, 540, True), (970, 550, False), (980, 560, False)], 0, "Beginning of route"),
# Multiple points - middle of route
([(950, 530, True), (960, 540, True), (970, 550, False), (980, 560, False)], 1, "Middle of route"),
]
for route_points_3d, frame_index, description in test_cases:
print(f"Testing: {description}")
try:
test_frame = frame.copy()
draw_3d_route(test_frame, route_points_3d, frame_index)
print(f"{description} - OK")
except Exception as e:
print(f"{description} - Failed: {e}")
return False
print("All draw_3d_route tests passed!")
return True
if __name__ == "__main__":
route_success = test_route_transition()
draw_success = test_draw_3d_route()
if route_success and draw_success:
print("✅ All transition tests PASSED")
sys.exit(0)
else:
print("❌ Some transition tests FAILED")
sys.exit(1)

75
test_video_generator.py Normal file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""
Test script to verify the enhanced 3D video generator works without overflow errors
"""
import sys
import os
sys.path.append('/home/pi/Desktop/traccar_animation')
from py_scripts.video_3d_generator import create_space_entry_frame
import numpy as np
def test_space_entry_frame():
"""Test the space entry frame generation"""
print("Testing space entry frame generation...")
# Sample position data
start_pos = {
'latitude': 45.7749,
'longitude': -122.4194,
'speed': 50,
'deviceTime': '2025-07-08 12:00:00'
}
# Test parameters
center_lat = 45.7749
center_lon = -122.4194
min_lat = 45.7000
max_lat = 45.8500
min_lon = -122.5000
max_lon = -122.3500
width = 1920
height = 1080
# Test multiple frames to ensure no overflow
for frame_index in range(0, 90, 10): # Test every 10th frame
print(f"Testing frame {frame_index}/90...")
try:
frame = create_space_entry_frame(
start_pos, center_lat, center_lon,
min_lat, max_lat, min_lon, max_lon,
width, height, frame_index, 90
)
# Check frame integrity
if frame is None:
print(f"ERROR: Frame {frame_index} is None")
return False
if frame.shape != (height, width, 3):
print(f"ERROR: Frame {frame_index} has wrong shape: {frame.shape}")
return False
# Check for valid pixel values
if np.any(frame < 0) or np.any(frame > 255):
print(f"ERROR: Frame {frame_index} has invalid pixel values")
return False
print(f"Frame {frame_index} OK - Shape: {frame.shape}, Min: {np.min(frame)}, Max: {np.max(frame)}")
except Exception as e:
print(f"ERROR: Frame {frame_index} failed: {e}")
return False
print("All space entry frames generated successfully!")
return True
if __name__ == "__main__":
success = test_space_entry_frame()
if success:
print("✅ Space entry frame generation test PASSED")
sys.exit(0)
else:
print("❌ Space entry frame generation test FAILED")
sys.exit(1)