updated versions

This commit is contained in:
2025-07-09 16:39:51 +03:00
parent 507f526433
commit 35d3bb8442
21 changed files with 23620 additions and 136873 deletions

View File

@@ -3,12 +3,15 @@ from kivy.uix.screenmanager import Screen
import os
import json
import math
from datetime import datetime
from kivy.clock import Clock
from kivy.properties import StringProperty, NumericProperty, AliasProperty
from py_scripts.utils import (
process_preview_util, optimize_route_entries_util
)
from py_scripts.video_3d_generator import generate_3d_video_animation
from py_scripts.advanced_3d_generator import Advanced3DGenerator
from py_scripts.blender_animator import BlenderGPSAnimator
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.label import Label
@@ -238,89 +241,128 @@ class CreateAnimationScreen(Screen):
)
def show_video_generation_options(self):
"""Show popup with video generation mode options"""
"""Show popup with video generation mode options including new advanced animations"""
from kivy.uix.popup import Popup
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
layout = BoxLayout(orientation='vertical', spacing=15, padding=15)
layout = BoxLayout(orientation='vertical', spacing=12, padding=15)
# Title
title_label = Label(
text="Choose Video Generation Mode",
font_size=18,
text="Choose Animation Style & Quality",
font_size=20,
size_hint_y=None,
height=40,
color=(1, 1, 1, 1)
)
layout.add_widget(title_label)
# Test mode description
test_layout = BoxLayout(orientation='vertical', spacing=5)
test_title = Label(
text="🏃‍♂️ 720p Test Mode (Fast)",
# Classic 3D Mode
classic_layout = BoxLayout(orientation='vertical', spacing=5)
classic_title = Label(
text="🏃‍♂️ Classic 3D (Original Pipeline)",
font_size=16,
size_hint_y=None,
height=30,
color=(0.2, 0.8, 0.2, 1)
)
test_desc = Label(
text="Resolution: 1280x720\n• Frame rate: 30 FPS\n~3x faster generation\nPerfect for quick previews",
font_size=12,
classic_desc = Label(
text="Traditional OpenCV/PIL approach\nFast generation\nGood for simple tracks\n• Test (720p) or Production (2K)",
font_size=11,
size_hint_y=None,
height=80,
height=70,
color=(0.9, 0.9, 0.9, 1),
halign="left",
valign="middle"
)
test_desc.text_size = (None, None)
test_layout.add_widget(test_title)
test_layout.add_widget(test_desc)
layout.add_widget(test_layout)
classic_desc.text_size = (None, None)
classic_layout.add_widget(classic_title)
classic_layout.add_widget(classic_desc)
layout.add_widget(classic_layout)
# Test mode button
test_btn = Button(
text="Generate 720p Test Video",
# Classic buttons
classic_btn_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=None, height=45)
classic_test_btn = Button(
text="Classic 720p",
background_color=(0.2, 0.8, 0.2, 1),
size_hint_y=None,
height=50,
font_size=14
font_size=12
)
layout.add_widget(test_btn)
classic_prod_btn = Button(
text="Classic 2K",
background_color=(0.3, 0.6, 0.3, 1),
font_size=12
)
classic_btn_layout.add_widget(classic_test_btn)
classic_btn_layout.add_widget(classic_prod_btn)
layout.add_widget(classic_btn_layout)
# Production mode description
prod_layout = BoxLayout(orientation='vertical', spacing=5)
prod_title = Label(
text="🎯 2K Production Mode (High Quality)",
# Advanced Pydeck/Plotly Mode
advanced_layout = BoxLayout(orientation='vertical', spacing=5)
advanced_title = Label(
text="🚀 Advanced 3D (Pydeck + Plotly)",
font_size=16,
size_hint_y=None,
height=30,
color=(0.8, 0.2, 0.2, 1)
color=(0.2, 0.6, 0.9, 1)
)
prod_desc = Label(
text="Resolution: 2560x1440\n• Frame rate: 60 FPS\n• Cinema-quality results\n• Ultra-detailed visuals",
font_size=12,
advanced_desc = Label(
text="Professional geospatial visualization\n• Interactive 3D terrain\n• Advanced camera movements\n• High-quality animations",
font_size=11,
size_hint_y=None,
height=80,
height=70,
color=(0.9, 0.9, 0.9, 1),
halign="left",
valign="middle"
)
prod_desc.text_size = (None, None)
prod_layout.add_widget(prod_title)
prod_layout.add_widget(prod_desc)
layout.add_widget(prod_layout)
advanced_desc.text_size = (None, None)
advanced_layout.add_widget(advanced_title)
advanced_layout.add_widget(advanced_desc)
layout.add_widget(advanced_layout)
# Production mode button
prod_btn = Button(
text="Generate 2K Production Video",
background_color=(0.8, 0.2, 0.2, 1),
# Advanced button
advanced_btn = Button(
text="Generate Advanced 3D Animation",
background_color=(0.2, 0.6, 0.9, 1),
size_hint_y=None,
height=50,
font_size=14
height=45,
font_size=13
)
layout.add_widget(prod_btn)
layout.add_widget(advanced_btn)
# Blender Cinema Mode
blender_layout = BoxLayout(orientation='vertical', spacing=5)
blender_title = Label(
text="<EFBFBD> Cinema Quality (Blender)",
font_size=16,
size_hint_y=None,
height=30,
color=(0.9, 0.6, 0.2, 1)
)
blender_desc = Label(
text="• Professional 3D rendering\n• Photorealistic visuals\n• Cinema-grade quality\n• Longer processing time",
font_size=11,
size_hint_y=None,
height=70,
color=(0.9, 0.9, 0.9, 1),
halign="left",
valign="middle"
)
blender_desc.text_size = (None, None)
blender_layout.add_widget(blender_title)
blender_layout.add_widget(blender_desc)
layout.add_widget(blender_layout)
# Blender button
blender_btn = Button(
text="Generate Blender Cinema Animation",
background_color=(0.9, 0.6, 0.2, 1),
size_hint_y=None,
height=45,
font_size=13
)
layout.add_widget(blender_btn)
# Cancel button
cancel_btn = Button(
@@ -333,23 +375,279 @@ class CreateAnimationScreen(Screen):
layout.add_widget(cancel_btn)
popup = Popup(
title="Select Video Generation Mode",
title="Select Animation Style",
content=layout,
size_hint=(0.9, 0.8),
size_hint=(0.95, 0.9),
auto_dismiss=False
)
def start_test_mode(instance):
def start_classic_test(instance):
popup.dismiss()
self.generate_3d_video_test_mode()
def start_production_mode(instance):
def start_classic_production(instance):
popup.dismiss()
self.generate_3d_video_production_mode()
def start_advanced_3d(instance):
popup.dismiss()
self.generate_advanced_3d_animation()
def start_blender_animation(instance):
popup.dismiss()
self.generate_blender_animation()
test_btn.bind(on_press=start_test_mode)
prod_btn.bind(on_press=start_production_mode)
classic_test_btn.bind(on_press=start_classic_test)
classic_prod_btn.bind(on_press=start_classic_production)
advanced_btn.bind(on_press=start_advanced_3d)
blender_btn.bind(on_press=start_blender_animation)
cancel_btn.bind(on_press=lambda x: popup.dismiss())
popup.open()
def generate_advanced_3d_animation(self):
"""Generate advanced 3D animation using Pydeck and Plotly"""
# Show processing popup
layout = BoxLayout(orientation='vertical', spacing=10, padding=10)
label = Label(text="Initializing advanced 3D animation...")
progress = ProgressBar(max=100, value=0)
layout.add_widget(label)
layout.add_widget(progress)
popup = Popup(
title="Generating Advanced 3D Animation",
content=layout,
size_hint=(0.9, None),
size=(0, 200),
auto_dismiss=False
)
popup.open()
def run_advanced_animation():
try:
# Update status
def update_status(progress_val, status_text):
def _update(dt):
progress.value = progress_val
label.text = status_text
Clock.schedule_once(_update, 0)
project_folder = os.path.join(RESOURCES_FOLDER, "projects", self.project_name)
positions_path = os.path.join(project_folder, "positions.json")
if not os.path.exists(positions_path):
update_status(0, "Error: No GPS data found")
Clock.schedule_once(lambda dt: popup.dismiss(), 2)
return
update_status(10, "Loading GPS data...")
# Check dependencies first
generator = Advanced3DGenerator(project_folder)
generator.check_dependencies()
update_status(20, "Processing GPS coordinates...")
df = generator.load_gps_data(positions_path)
update_status(40, "Creating 3D visualization frames...")
output_video_path = os.path.join(project_folder, f"{self.project_name}_advanced_3d_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4")
# Progress callback for the generator
def generator_progress(progress, message):
update_status(40 + (progress * 0.4), message) # Map 0-100% to 40-80%
update_status(80, "Rendering video...")
success = generator.generate_3d_animation(
positions_path,
output_video_path,
style='advanced',
progress_callback=generator_progress
)
if success:
update_status(100, "Advanced 3D animation complete!")
output_path = output_video_path
else:
raise Exception("Failed to generate video")
def show_success(dt):
popup.dismiss()
self.show_success_popup(
"Advanced 3D Animation Complete!",
f"Your high-quality 3D animation has been saved to:\n{output_path}",
output_path
)
Clock.schedule_once(show_success, 1)
except Exception as e:
error_message = str(e)
def show_error(dt):
popup.dismiss()
self.show_error_popup("Advanced Animation Error", error_message)
Clock.schedule_once(show_error, 0)
# Schedule the animation generation
Clock.schedule_once(lambda dt: run_advanced_animation(), 0.5)
def generate_blender_animation(self):
"""Generate cinema-quality animation using Blender"""
# Show processing popup
layout = BoxLayout(orientation='vertical', spacing=10, padding=10)
label = Label(text="Initializing Blender rendering pipeline...")
progress = ProgressBar(max=100, value=0)
layout.add_widget(label)
layout.add_widget(progress)
popup = Popup(
title="Generating Blender Cinema Animation",
content=layout,
size_hint=(0.9, None),
size=(0, 200),
auto_dismiss=False
)
popup.open()
def run_blender_animation():
try:
# Update status
def update_status(progress_val, status_text):
def _update(dt):
progress.value = progress_val
label.text = status_text
Clock.schedule_once(_update, 0)
project_folder = os.path.join(RESOURCES_FOLDER, "projects", self.project_name)
positions_path = os.path.join(project_folder, "positions.json")
if not os.path.exists(positions_path):
update_status(0, "Error: No GPS data found")
Clock.schedule_once(lambda dt: popup.dismiss(), 2)
return
update_status(10, "Loading GPS data into Blender...")
# Check dependencies first
animator = BlenderGPSAnimator(project_folder)
animator.check_dependencies()
update_status(25, "Processing GPS coordinates...")
gps_data = animator.load_gps_data(positions_path)
output_video_path = os.path.join(project_folder, f"{self.project_name}_blender_cinema_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4")
# Progress callback for the animator
def animator_progress(progress, message):
update_status(25 + (progress * 0.6), message) # Map 0-100% to 25-85%
update_status(85, "Rendering cinema-quality video...")
success = animator.create_gps_animation(
positions_path,
output_video_path,
progress_callback=animator_progress
)
if success:
update_status(100, "Blender cinema animation complete!")
output_path = output_video_path
else:
raise Exception("Failed to render Blender animation")
def show_success(dt):
popup.dismiss()
self.show_success_popup(
"Blender Cinema Animation Complete!",
f"Your cinema-quality animation has been rendered to:\n{output_path}",
output_path
)
Clock.schedule_once(show_success, 1)
except Exception as e:
error_message = str(e)
def show_error(dt):
popup.dismiss()
self.show_error_popup("Blender Animation Error", error_message)
Clock.schedule_once(show_error, 0)
# Schedule the animation generation
Clock.schedule_once(lambda dt: run_blender_animation(), 0.5)
def show_success_popup(self, title, message, file_path=None):
"""Show success popup with option to open file location"""
layout = BoxLayout(orientation='vertical', spacing=10, padding=10)
success_label = Label(
text=message,
text_size=(400, None),
halign="center",
valign="middle"
)
layout.add_widget(success_label)
button_layout = BoxLayout(orientation='horizontal', spacing=10, size_hint_y=None, height=50)
if file_path:
open_btn = Button(text="Open Folder", background_color=(0.2, 0.8, 0.2, 1))
open_btn.bind(on_press=lambda x: self.open_file_location(file_path))
button_layout.add_widget(open_btn)
ok_btn = Button(text="OK", background_color=(0.2, 0.6, 0.9, 1))
button_layout.add_widget(ok_btn)
layout.add_widget(button_layout)
popup = Popup(
title=title,
content=layout,
size_hint=(0.8, None),
size=(0, 250),
auto_dismiss=False
)
ok_btn.bind(on_press=lambda x: popup.dismiss())
popup.open()
def show_error_popup(self, title, message):
"""Show error popup"""
layout = BoxLayout(orientation='vertical', spacing=10, padding=10)
error_label = Label(
text=f"Error: {message}",
text_size=(400, None),
halign="center",
valign="middle",
color=(1, 0.3, 0.3, 1)
)
layout.add_widget(error_label)
ok_btn = Button(text="OK", background_color=(0.8, 0.2, 0.2, 1), size_hint_y=None, height=50)
layout.add_widget(ok_btn)
popup = Popup(
title=title,
content=layout,
size_hint=(0.8, None),
size=(0, 200),
auto_dismiss=False
)
ok_btn.bind(on_press=lambda x: popup.dismiss())
popup.open()
def open_file_location(self, file_path):
"""Open file location in system file manager"""
import subprocess
import platform
folder_path = os.path.dirname(file_path)
try:
if platform.system() == "Linux":
subprocess.run(["xdg-open", folder_path])
elif platform.system() == "Darwin": # macOS
subprocess.run(["open", folder_path])
elif platform.system() == "Windows":
subprocess.run(["explorer", folder_path])
except Exception as e:
print(f"Could not open folder: {e}")