/
Anton_Zelentsov
/
space-navigation-api
Обзор
Документация
Войти
/
Anton_Zelentsov
/
space-navigation-api
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
interface.html
510 строк
22 KB
Anton Zelentsov
Develop: space navigation API with 3 files
14 апр 2026, 20:20
14 апр 2026, 20:20
9e41848
Код
Авторство
О чём код?
<!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Space Navigation API - Астронавигация</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; background: linear-gradient(135deg, #0a0e27 0%, #1a1a3e 100%); min-height: 100vh; padding: 20px; } .container { max-width: 1400px; margin: 0 auto; } h1 { text-align: center; color: white; margin-bottom: 10px; font-size: 2.5em; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); } .subtitle { text-align: center; color: #a0a0c0; margin-bottom: 30px; font-size: 1.1em; } .tasks-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(420px, 1fr)); gap: 25px; margin-bottom: 30px; } .task-card { background: linear-gradient(135deg, #ffffff 0%, #f5f5ff 100%); border-radius: 15px; padding: 25px; box-shadow: 0 10px 30px rgba(0,0,0,0.3); transition: transform 0.3s ease, box-shadow 0.3s ease; } .task-card:hover { transform: translateY(-5px); box-shadow: 0 15px 40px rgba(0,0,0,0.4); } .task-title { font-size: 1.6em; color: #667eea; margin-bottom: 20px; border-bottom: 3px solid #667eea; padding-bottom: 10px; display: flex; align-items: center; gap: 10px; } .input-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; color: #333; font-weight: bold; font-size: 14px; } input { width: 100%; padding: 10px; border: 2px solid #e0e0e0; border-radius: 8px; font-size: 14px; transition: border-color 0.3s ease; } input:focus { outline: none; border-color: #667eea; } small { display: block; margin-top: 5px; color: #888; font-size: 11px; } button { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; padding: 12px 24px; border-radius: 8px; cursor: pointer; font-size: 16px; font-weight: bold; width: 100%; margin-top: 10px; transition: opacity 0.3s ease, transform 0.2s ease; } button:hover { opacity: 0.9; transform: scale(0.98); } .result { margin-top: 20px; padding: 15px; background: #f8f9fa; border-radius: 8px; border-left: 4px solid #667eea; max-height: 400px; overflow: auto; font-size: 13px; } .result pre { white-space: pre-wrap; word-wrap: break-word; font-family: 'Courier New', monospace; font-size: 12px; margin: 0; } .success { color: #28a745; font-weight: bold; margin-bottom: 10px; } .error { color: #dc3545; font-weight: bold; margin-bottom: 10px; } .info { color: #17a2b8; font-weight: bold; margin-bottom: 10px; } .window-item { background: white; padding: 10px; margin-bottom: 10px; border-radius: 5px; border-left: 3px solid #28a745; } .stat-badge { display: inline-block; padding: 3px 8px; background: #667eea; color: white; border-radius: 12px; font-size: 11px; margin-right: 10px; } @media (max-width: 768px) { .tasks-grid { grid-template-columns: 1fr; } h1 { font-size: 1.8em; } } </style> </head> <body> <div class="container"> <h1>🚀 Space Navigation API</h1> <div class="subtitle">Гравитационные маневры | Окна видимости | Поиск созвездий</div> <div class="tasks-grid"> <!-- ЗАДАЧА 1: Гравитационный маневр --> <div class="task-card"> <div class="task-title"> <span>📡</span> <span>Задача 1: Гравитационный маневр</span> </div> <div class="input-group"> <label>Масса планеты (кг):</label> <input type="number" id="mass_planet" value="5.97e24" step="1e23"> <small>Пример: Земля - 5.97×10²⁴ кг</small> </div> <div class="input-group"> <label>Скорость на бесконечности (м/с):</label> <input type="number" id="v_inf_in" value="15000"> <small>Скорость аппарата до маневра</small> </div> <div class="input-group"> <label>Мин. радиус перицентра (м):</label> <input type="number" id="min_r" value="6371000"> <small>Минимальное расстояние до планеты</small> </div> <div class="input-group"> <label>Скорость планеты (м/с):</label> <input type="number" id="v_planet" value="29780"> <small>Орбитальная скорость планеты</small> </div> <button onclick="runTask1()">🚀 Рассчитать гравитационный маневр</button> <div class="result" id="result1"> <div class="info">💡 Нажмите кнопку для расчета</div> </div> </div> <!-- ЗАДАЧА 2: Окно видимости --> <div class="task-card"> <div class="task-title"> <span>👁️</span> <span>Задача 2: Окна видимости</span> </div> <div class="input-group"> <label>🌍 Наблюдатель (планета):</label> <select id="observer_preset" onchange="loadObserverPreset()" style="width:100%; padding:8px; margin-bottom:10px;"> <option value="earth">Земля</option> <option value="mars">Марс</option> <option value="jupiter">Юпитер</option> </select> </div> <div class="input-group"> <label>Радиус орбиты наблюдателя (м):</label> <input type="number" id="observer_radius" value="149600000000"> <small>Земля: 149.6 млн км</small> </div> <div class="input-group"> <label>Период наблюдателя (дни):</label> <input type="number" id="observer_period" value="365.25"> <small>Земля: 365.25 дней</small> </div> <div class="input-group"> <label>🎯 Цель (планета):</label> <select id="target_preset" onchange="loadTargetPreset()" style="width:100%; padding:8px; margin-bottom:10px;"> <option value="mars">Марс</option> <option value="venus">Венера</option> <option value="jupiter">Юпитер</option> </select> </div> <div class="input-group"> <label>Радиус орбиты цели (м):</label> <input type="number" id="target_radius" value="227900000000"> <small>Марс: 227.9 млн км</small> </div> <div class="input-group"> <label>Период цели (дни):</label> <input type="number" id="target_period" value="687"> <small>Марс: 687 дней</small> </div> <div class="input-group"> <label>Длительность наблюдения (дни):</label> <input type="number" id="duration" value="500"> <small>Рекомендуется: 500-1000 дней</small> </div> <button onclick="runTask2()">👁️ Найти окна видимости</button> <div class="result" id="result2"> <div class="info">💡 Нажмите кнопку для поиска</div> </div> </div> <!-- ЗАДАЧА 3: Поиск созвездия --> <div class="task-card"> <div class="task-title"> <span>⭐</span> <span>Задача 3: Поиск созвездия</span> </div> <div class="input-group"> <label>Наблюдаемые звезды (через запятую):</label> <input type="text" id="observed" value="Sirius,Betelgeuse,Rigel"> <small>Введите названия звезд через запятую</small> </div> <div class="input-group"> <label>Звезды созвездия (через запятую):</label> <input type="text" id="constellation" value="Betelgeuse,Rigel,Bellatrix"> <small>Эталонные звезды созвездия</small> </div> <div class="input-group"> <label>Название созвездия:</label> <input type="text" id="const_name" value="Орион"> <small>Название искомого созвездия</small> </div> <div class="input-group"> <label>Порог совпадения (%):</label> <input type="number" id="threshold" value="50" min="0" max="100"> <small>Минимальный процент совпадения</small> </div> <button onclick="runTask3()">⭐ Найти созвездие</button> <div class="result" id="result3"> <div class="info">💡 Нажмите кнопку для поиска</div> </div> </div> </div> </div> <script> const API_URL = 'http://127.0.0.1:8000'; // Предустановки для задачи 2 const presets = { earth: { radius: 149600000000, period: 365.25, name: "Земля" }, mars: { radius: 227900000000, period: 687, name: "Марс" }, venus: { radius: 108200000000, period: 225, name: "Венера" }, jupiter: { radius: 778500000000, period: 4333, name: "Юпитер" } }; function loadObserverPreset() { const preset = document.getElementById('observer_preset').value; if (presets[preset]) { document.getElementById('observer_radius').value = presets[preset].radius; document.getElementById('observer_period').value = presets[preset].period; } } function loadTargetPreset() { const preset = document.getElementById('target_preset').value; if (presets[preset]) { document.getElementById('target_radius').value = presets[preset].radius; document.getElementById('target_period').value = presets[preset].period; } } // ЗАДАЧА 1 async function runTask1() { const data = { mass_planet: parseFloat(document.getElementById('mass_planet').value), v_inf_in: parseFloat(document.getElementById('v_inf_in').value), min_r_periapsis: parseFloat(document.getElementById('min_r').value), v_planet: parseFloat(document.getElementById('v_planet').value) }; showLoading('result1'); try { const response = await fetch(`${API_URL}/api/task1`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data) }); const result = await response.json(); if (result.success) { document.getElementById('result1').innerHTML = ` <div class="success">✅ Результат гравитационного маневра:</div> <div class="window-item"> <span class="stat-badge">📊</span> <strong>Конечная скорость:</strong> ${result.result.v_out_mps.toLocaleString()} м/с<br> <span class="stat-badge">⚡</span> <strong>Изменение скорости:</strong> +${result.result.delta_v_mps.toLocaleString()} м/с<br> <span class="stat-badge">🔄</span> <strong>Угол отклонения:</strong> ${result.result.deflection_angle_deg}°<br> <span class="stat-badge">🎯</span> <strong>Прирост скорости:</strong> ${((result.result.delta_v_mps / result.result.v_out_mps) * 100).toFixed(1)}% </div> <pre style="margin-top:10px;">${JSON.stringify(result.result, null, 2)}</pre> `; } else { document.getElementById('result1').innerHTML = ` <div class="error">❌ Ошибка: ${result.error}</div> `; } } catch (error) { document.getElementById('result1').innerHTML = ` <div class="error">❌ Ошибка соединения: ${error.message}<br> Убедитесь, что сервер запущен: python final_app.py</div> `; } } // ЗАДАЧА 2 async function runTask2() { const data = { observer: { radius: parseFloat(document.getElementById('observer_radius').value), period: parseFloat(document.getElementById('observer_period').value) }, target: { radius: parseFloat(document.getElementById('target_radius').value), period: parseFloat(document.getElementById('target_period').value) }, start_time: 0, duration_days: parseFloat(document.getElementById('duration').value) }; showLoading('result2'); try { const response = await fetch(`${API_URL}/api/task2`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data) }); const result = await response.json(); if (result.success) { if (result.windows.length === 0) { document.getElementById('result2').innerHTML = ` <div class="info">ℹ️ Окон видимости не найдено за ${data.duration_days} дней</div> <div class="window-item">💡 Попробуйте увеличить длительность наблюдения до 500-1000 дней</div> `; } else { let windowsHtml = `<div class="success">✅ Найдено ${result.total_windows} окон видимости:</div>`; result.windows.forEach((window, idx) => { windowsHtml += ` <div class="window-item"> <strong>📅 Окно ${idx + 1}:</strong><br> ▸ Начало: ${window.start_date}<br> ▸ Длительность: ${window.duration} дней<br> ▸ Макс. элонгация: ${window.max_elongation}°<br> ▸ Мин. расстояние: ${window.min_distance_km} млн км </div> `; }); windowsHtml += `<pre style="margin-top:10px;">${JSON.stringify(result.windows, null, 2)}</pre>`; document.getElementById('result2').innerHTML = windowsHtml; } } else { document.getElementById('result2').innerHTML = ` <div class="error">❌ Ошибка: ${result.error}</div> `; } } catch (error) { document.getElementById('result2').innerHTML = ` <div class="error">❌ Ошибка соединения: ${error.message}<br> Убедитесь, что сервер запущен: python final_app.py</div> `; } } // ЗАДАЧА 3 async function runTask3() { const observedStars = document.getElementById('observed').value.split(',').map(s => ({name: s.trim()})); const constellationStars = document.getElementById('constellation').value.split(',').map(s => s.trim()); const constName = document.getElementById('const_name').value; const threshold = parseFloat(document.getElementById('threshold').value); const data = { observed_stars: observedStars, constellation_stars: constellationStars, constellation_name: constName, tolerance: 0.1 }; showLoading('result3'); try { const response = await fetch(`${API_URL}/api/task3`, { method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(data) }); const result = await response.json(); if (result.success) { const matchPercent = result.result.match_percentage; const isMatch = matchPercent >= threshold; if (isMatch) { document.getElementById('result3').innerHTML = ` <div class="success">✅ Найдено созвездие <strong>"${constName}"</strong>!</div> <div class="window-item"> <span class="stat-badge">🎯</span> <strong>Совпадение:</strong> ${matchPercent}%<br> <span class="stat-badge">⭐</span> <strong>Совпавшие звезды:</strong> ${result.result.matches.join(', ')}<br> <span class="stat-badge">📊</span> <strong>Найдено звезд:</strong> ${result.result.matches.length} из ${constellationStars.length} </div> <pre style="margin-top:10px;">${JSON.stringify(result.result, null, 2)}</pre> `; } else { document.getElementById('result3').innerHTML = ` <div class="error">❌ Созвездие "${constName}" не найдено</div> <div class="window-item"> Совпадение: ${matchPercent}% (нужно ${threshold}%)<br> Совпавшие звезды: ${result.result.matches.join(', ') || 'нет'}<br> 💡 Попробуйте другие звезды или снизьте порог совпадения </div> `; } } else { document.getElementById('result3').innerHTML = ` <div class="error">❌ Ошибка: ${result.error}</div> `; } } catch (error) { document.getElementById('result3').innerHTML = ` <div class="error">❌ Ошибка соединения: ${error.message}<br> Убедитесь, что сервер запущен: python final_app.py</div> `; } } function showLoading(elementId) { document.getElementById(elementId).innerHTML = '<div class="info">⏳ Выполняется запрос...</div>'; } </script> </body> </html>