From f4014a08a124081f3d597caca9c84fecc26ebc60 Mon Sep 17 00:00:00 2001 From: emelianov Date: Wed, 27 May 2026 12:00:52 +0300 Subject: [PATCH] =?UTF-8?q?=D1=81=D1=80=D0=B0=D0=B2=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20TLE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/ballistics/TlePointRequestDTO.kt | 8 ++ .../controller/TLEController.kt | 7 +- .../pcp_request_service/service/TLEService.kt | 34 +++++++ .../controller/TleComparisonController.kt | 98 ++++++++++++++----- .../dto/tlecomparison/TleComparisonDTO.kt | 31 +++++- .../service/BallisticsService.kt | 11 +++ .../static/tle_comparison_scripts.js | 89 ++++++++++++++--- .../resources/templates/tle-comparison.html | 21 ++-- 8 files changed, 247 insertions(+), 52 deletions(-) create mode 100644 libs/pcp-types-lib/src/main/kotlin/space/nstart/pcp/pcp_types_lib/dto/ballistics/TlePointRequestDTO.kt diff --git a/libs/pcp-types-lib/src/main/kotlin/space/nstart/pcp/pcp_types_lib/dto/ballistics/TlePointRequestDTO.kt b/libs/pcp-types-lib/src/main/kotlin/space/nstart/pcp/pcp_types_lib/dto/ballistics/TlePointRequestDTO.kt new file mode 100644 index 0000000..bdb30e3 --- /dev/null +++ b/libs/pcp-types-lib/src/main/kotlin/space/nstart/pcp/pcp_types_lib/dto/ballistics/TlePointRequestDTO.kt @@ -0,0 +1,8 @@ +package space.nstart.pcp.pcp_types_lib.dto.ballistics + +import java.time.LocalDateTime + +class TlePointRequestDTO( + var tle: TLEDTO = TLEDTO(), + var time: LocalDateTime = LocalDateTime.now() +) diff --git a/services/pcp-ballistics-service/src/main/kotlin/space/nstart/pcp/pcp_request_service/controller/TLEController.kt b/services/pcp-ballistics-service/src/main/kotlin/space/nstart/pcp/pcp_request_service/controller/TLEController.kt index 7a6c6d8..c7e06e5 100644 --- a/services/pcp-ballistics-service/src/main/kotlin/space/nstart/pcp/pcp_request_service/controller/TLEController.kt +++ b/services/pcp-ballistics-service/src/main/kotlin/space/nstart/pcp/pcp_request_service/controller/TLEController.kt @@ -1,15 +1,13 @@ package space.nstart.pcp.pcp_request_service.controller -import ballistics.types.OrbitalPoint import org.springframework.beans.factory.annotation.Autowired -import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import space.nstart.pcp.pcp_request_service.service.TLEService -import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO +import space.nstart.pcp.pcp_types_lib.dto.ballistics.TlePointRequestDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.TleRvaRequestDTO @RestController @@ -23,6 +21,9 @@ class TLEController { @PostMapping("/parse") fun orbit(@RequestBody tle : TLEDTO) = tleService.parseTLE(tle) + @PostMapping("/point") + fun point(@RequestBody req: TlePointRequestDTO) = tleService.point(req) + @PostMapping("/rva") fun rva(@RequestBody req : TleRvaRequestDTO) = tleService.rva(req) diff --git a/services/pcp-ballistics-service/src/main/kotlin/space/nstart/pcp/pcp_request_service/service/TLEService.kt b/services/pcp-ballistics-service/src/main/kotlin/space/nstart/pcp/pcp_request_service/service/TLEService.kt index e44b004..5bd8fc7 100644 --- a/services/pcp-ballistics-service/src/main/kotlin/space/nstart/pcp/pcp_request_service/service/TLEService.kt +++ b/services/pcp-ballistics-service/src/main/kotlin/space/nstart/pcp/pcp_request_service/service/TLEService.kt @@ -1,7 +1,9 @@ package space.nstart.pcp.pcp_request_service.service import ballistics.Ballistics +import ballistics.orbitalPoints.timeStepper.TLEStepper import ballistics.types.BallisticsError +import ballistics.types.EarthType import ballistics.types.PPI import ballistics.types.TLE import ballistics.types.TLEParams @@ -15,6 +17,7 @@ import space.nstart.pcp.pcp_request_service.configuration.CustomValidationExcept import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.RadioVisibilityAreaDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO +import space.nstart.pcp.pcp_types_lib.dto.ballistics.TlePointRequestDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.TargetPositionDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.TleRvaRequestDTO import kotlin.math.PI @@ -47,6 +50,37 @@ class TLEService() { + + fun point(req: TlePointRequestDTO): OrbPointDTO { + val bal = Ballistics() + val tleParams = try { + bal.getTLEParams(TLE(req.tle.first, req.tle.second), req.tle.header ?: "empty") + } catch (ex: Exception) { + throw CustomValidationException("Ошибка формата TLE : ${ex.message}") + } + if (req.time < tleParams.time) { + throw CustomValidationException("Время расчета должно быть не раньше эпохи TLE ${tleParams.time}") + } + + val point = try { + val stepper = TLEStepper(req.tle.first, req.tle.second, EarthType.PZ90d02) + stepper.calculate(fromDateTime(req.time)) + } catch (ex: Exception) { + throw CustomErrorException("Ошибка расчета положения по TLE : ${ex.message}") + } + + return OrbPointDTO( + toDateTime(point.t), + point.vit.toLong(), + point.v.x, + point.v.y, + point.v.z, + point.r.x, + point.r.y, + point.r.z + ) + } + fun rva(req : TleRvaRequestDTO) : Iterable { val bal = Ballistics() diff --git a/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/TleComparisonController.kt b/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/TleComparisonController.kt index 8b8cae2..0cf22ed 100644 --- a/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/TleComparisonController.kt +++ b/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/controller/TleComparisonController.kt @@ -4,18 +4,23 @@ import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController +import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO import space.nstart.pcp.slots_service.configuration.CustomValidationException import space.nstart.pcp.slots_service.dto.tlecomparison.TleCompareRequestDTO import space.nstart.pcp.slots_service.dto.tlecomparison.TleCompareResponseDTO import space.nstart.pcp.slots_service.dto.tlecomparison.TleCompareRowDTO import space.nstart.pcp.slots_service.dto.tlecomparison.TleParsedDTO +import space.nstart.pcp.slots_service.dto.tlecomparison.TlePositionDTO +import space.nstart.pcp.slots_service.dto.tlecomparison.TlePositionDeltaDTO import space.nstart.pcp.slots_service.dto.tlecomparison.TleTextRequestDTO import space.nstart.pcp.slots_service.service.BallisticsService +import java.time.Duration import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.Locale import kotlin.math.abs +import kotlin.math.sqrt @RestController @RequestMapping("/api/tle-comparison") @@ -29,12 +34,38 @@ class TleComparisonController( @PostMapping("/compare") fun compare(@RequestBody request: TleCompareRequestDTO): TleCompareResponseDTO { - val first = ballisticsService.parseTle(parseTleText(request.first)) - val second = ballisticsService.parseTle(parseTleText(request.second)) + val firstTle = parseTleText(request.first) + val secondTle = parseTleText(request.second) + val firstParsed = ballisticsService.parseTle(firstTle) + val secondParsed = ballisticsService.parseTle(secondTle) + val calculationTime = request.time + ?: throw CustomValidationException("Задайте время сравнения TLE") + val firstEpoch = firstParsed.time + ?: throw CustomValidationException("Не удалось определить эпоху первого TLE") + val secondEpoch = secondParsed.time + ?: throw CustomValidationException("Не удалось определить эпоху второго TLE") + val maxEpoch = maxOf(firstEpoch, secondEpoch) + if (calculationTime < maxEpoch) { + throw CustomValidationException("Время сравнения должно быть не раньше максимальной эпохи TLE: $maxEpoch") + } + + val firstPoint = ballisticsService.tlePoint(firstTle, calculationTime).toPosition() + val secondPoint = ballisticsService.tlePoint(secondTle, calculationTime).toPosition() + val delta = TlePositionDeltaDTO( + dx = secondPoint.x - firstPoint.x, + dy = secondPoint.y - firstPoint.y, + dz = secondPoint.z - firstPoint.z, + norm = distance(secondPoint.x - firstPoint.x, secondPoint.y - firstPoint.y, secondPoint.z - firstPoint.z) + ) + return TleCompareResponseDTO( - first = first, - second = second, - rows = buildRows(first, second) + time = calculationTime, + firstEpoch = firstEpoch, + secondEpoch = secondEpoch, + first = firstPoint, + second = secondPoint, + radiusVectorDelta = delta, + rows = buildRows(firstPoint, secondPoint, delta) ) } @@ -69,23 +100,38 @@ class TleComparisonController( ) } - private fun buildRows(first: TleParsedDTO, second: TleParsedDTO): List = listOf( - textRow("satName", "Название", first.satName, second.satName), - textRow("noradId", "NORAD ID", first.noradId?.toString(), second.noradId?.toString()), - textRow("revolution", "Номер витка", first.revolution?.toString(), second.revolution?.toString()), - timeRow("time", "Эпоха", first.time, second.time), - numberRow("inclination", "Наклонение", first.inclination, second.inclination), - numberRow("ascendingNode", "ВУЗ", first.ascendingNode, second.ascendingNode), - numberRow("argPerigee", "Аргумент перигея", first.argPerigee, second.argPerigee), - numberRow("meanAnomaly", "Средняя аномалия", first.meanAnomaly, second.meanAnomaly), - numberRow("eccentricity", "Эксцентриситет", first.eccentricity, second.eccentricity), - numberRow("perigee", "Перигей", first.perigee, second.perigee), - numberRow("apogee", "Апогей", first.apogee, second.apogee), - numberRow("period", "Период", first.period, second.period), - numberRow("semiMajor", "Большая полуось", first.semiMajor, second.semiMajor), - numberRow("semiMinor", "Малая полуось", first.semiMinor, second.semiMinor), - numberRow("meanMotion", "Среднее движение", first.meanMotion, second.meanMotion), - numberRow("meanMotionTLE", "Среднее движение TLE", first.meanMotionTLE, second.meanMotionTLE) + private fun buildRows( + first: TlePositionDTO, + second: TlePositionDTO, + delta: TlePositionDeltaDTO + ): List = listOf( + timeRow("time", "Время расчета", first.time, second.time), + textRow("revolution", "Виток", first.revolution.toString(), second.revolution.toString()), + numberRow("x", "X радиус-вектора, м", first.x, second.x), + numberRow("y", "Y радиус-вектора, м", first.y, second.y), + numberRow("z", "Z радиус-вектора, м", first.z, second.z), + numberRow("radiusNorm", "Модуль радиус-вектора, м", first.radiusNorm, second.radiusNorm), + numberRow("vx", "Vx, м/с", first.vx, second.vx), + numberRow("vy", "Vy, м/с", first.vy, second.vy), + numberRow("vz", "Vz, м/с", first.vz, second.vz), + numberRow("velocityNorm", "Модуль скорости, м/с", first.velocityNorm, second.velocityNorm), + TleCompareRowDTO("dx", "ΔX = X2 - X1, м", first = null, second = null, delta = delta.dx.formatSignedNumber()), + TleCompareRowDTO("dy", "ΔY = Y2 - Y1, м", first = null, second = null, delta = delta.dy.formatSignedNumber()), + TleCompareRowDTO("dz", "ΔZ = Z2 - Z1, м", first = null, second = null, delta = delta.dz.formatSignedNumber()), + TleCompareRowDTO("radiusDeltaNorm", "|Δr|, м", first = null, second = null, delta = delta.norm.formatNumber()) + ) + + private fun OrbPointDTO.toPosition(): TlePositionDTO = TlePositionDTO( + time = time, + revolution = revolution, + x = x, + y = y, + z = z, + vx = vx, + vy = vy, + vz = vz, + radiusNorm = distance(x, y, z), + velocityNorm = distance(vx, vy, vz) ) private fun textRow(code: String, name: String, first: String?, second: String?): TleCompareRowDTO = @@ -100,7 +146,7 @@ class TleComparisonController( private fun timeRow(code: String, name: String, first: LocalDateTime?, second: LocalDateTime?): TleCompareRowDTO { val formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME val delta = if (first != null && second != null) { - val seconds = java.time.Duration.between(first, second).seconds + val seconds = Duration.between(first, second).seconds formatSecondsDelta(seconds) } else { null @@ -117,11 +163,13 @@ class TleComparisonController( delta = if (first != null && second != null) (second - first).formatSignedNumber() else null ) - private fun Double.formatNumber(): String = String.format(Locale.US, "%.8f", this) + private fun distance(x: Double, y: Double, z: Double): Double = sqrt(x * x + y * y + z * z) + + private fun Double.formatNumber(): String = String.format(Locale.US, "%.6f", this) private fun Double.formatSignedNumber(): String { val sign = if (this > 0) "+" else "" - return sign + String.format(Locale.US, "%.8f", this) + return sign + String.format(Locale.US, "%.6f", this) } private fun formatSecondsDelta(seconds: Long): String { diff --git a/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/dto/tlecomparison/TleComparisonDTO.kt b/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/dto/tlecomparison/TleComparisonDTO.kt index 6b89fbd..238b312 100644 --- a/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/dto/tlecomparison/TleComparisonDTO.kt +++ b/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/dto/tlecomparison/TleComparisonDTO.kt @@ -8,7 +8,8 @@ class TleTextRequestDTO( class TleCompareRequestDTO( var first: String = "", - var second: String = "" + var second: String = "", + var time: LocalDateTime? = null ) data class TleParsedDTO( @@ -32,6 +33,19 @@ data class TleParsedDTO( val meanMotionTLE: Double? = null ) +data class TlePositionDTO( + val time: LocalDateTime, + val revolution: Long, + val x: Double, + val y: Double, + val z: Double, + val vx: Double, + val vy: Double, + val vz: Double, + val radiusNorm: Double, + val velocityNorm: Double +) + data class TleCompareRowDTO( val code: String, val name: String, @@ -41,7 +55,18 @@ data class TleCompareRowDTO( ) data class TleCompareResponseDTO( - val first: TleParsedDTO, - val second: TleParsedDTO, + val time: LocalDateTime, + val firstEpoch: LocalDateTime, + val secondEpoch: LocalDateTime, + val first: TlePositionDTO, + val second: TlePositionDTO, + val radiusVectorDelta: TlePositionDeltaDTO, val rows: List ) + +data class TlePositionDeltaDTO( + val dx: Double, + val dy: Double, + val dz: Double, + val norm: Double +) diff --git a/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/service/BallisticsService.kt b/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/service/BallisticsService.kt index b268c6c..1b4865e 100644 --- a/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/service/BallisticsService.kt +++ b/services/pcp-ui-service/src/main/kotlin/space/nstart/pcp/slots_service/service/BallisticsService.kt @@ -11,6 +11,7 @@ import space.nstart.pcp.pcp_types_lib.dto.ballistics.FlightLineDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.OrbPointDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.SatelliteOrbitAvailabilityDTO import space.nstart.pcp.pcp_types_lib.dto.ballistics.TLEDTO +import space.nstart.pcp.pcp_types_lib.dto.ballistics.TlePointRequestDTO import space.nstart.pcp.slots_service.dto.tlecomparison.TleParsedDTO import space.nstart.pcp.slots_service.configuration.CustomErrorException import java.net.URI @@ -80,6 +81,16 @@ class BallisticsService (webClientBuilderProvider: ObjectProvider scheduleParse('first')); second?.addEventListener('input', () => scheduleParse('second')); + el('tle-comparison-time')?.addEventListener('change', validateCalculationTime); el('tle-compare-submit')?.addEventListener('click', compareTle); el('tle-compare-clear')?.addEventListener('click', clearPage); } @@ -26,6 +28,7 @@ if (!text.trim()) { state[side] = null; updateReference(side, null); + updateTimeLimits(); return; } setStatus(side, 'Разбор...', 'text-muted'); @@ -37,10 +40,12 @@ const parsed = await postJson('/api/tle-comparison/parse', { tle: getTleText(side) }); state[side] = parsed; updateReference(side, parsed); + updateTimeLimits(); setStatus(side, 'Разобрано', 'tle-parse-ok'); } catch (error) { state[side] = null; updateReference(side, null); + updateTimeLimits(); setStatus(side, error.message || 'Ошибка разбора', 'tle-parse-error'); } } @@ -49,21 +54,25 @@ showAlert(''); const first = getTleText('first'); const second = getTleText('second'); + const time = getCalculationTime(); if (!first.trim() || !second.trim()) { showAlert('Введите оба TLE для сравнения.', 'warning'); return; } + if (!time) { + showAlert('Задайте время расчета.', 'warning'); + return; + } + const minTime = maxEpoch(); + if (minTime && time < minTime) { + showAlert(`Время расчета должно быть не раньше максимальной эпохи TLE: ${formatDateTime(minTime)}.`, 'warning'); + return; + } setCompareLoading(true); try { - const response = await postJson('/api/tle-comparison/compare', { first, second }); - state.first = response.first; - state.second = response.second; - updateReference('first', response.first); - updateReference('second', response.second); - setStatus('first', 'Разобрано', 'tle-parse-ok'); - setStatus('second', 'Разобрано', 'tle-parse-ok'); - renderComparison(response.rows || []); + const response = await postJson('/api/tle-comparison/compare', { first, second, time }); + renderComparison(response); } catch (error) { showAlert(error.message || 'Не удалось выполнить сравнение TLE.', 'danger'); } finally { @@ -71,7 +80,8 @@ } } - function renderComparison(rows) { + function renderComparison(response) { + const rows = response?.rows || []; const body = el('tle-comparison-result-body'); const empty = el('tle-comparison-empty'); const wrap = el('tle-comparison-table-wrap'); @@ -98,9 +108,9 @@ empty.classList.add('d-none'); wrap.classList.remove('d-none'); if (meta) { - const firstEpoch = formatDateTime(state.first?.time); - const secondEpoch = formatDateTime(state.second?.time); - meta.textContent = `Эпохи: TLE 1 — ${firstEpoch || '—'}, TLE 2 — ${secondEpoch || '—'}`; + const deltaNorm = response.radiusVectorDelta?.norm; + const deltaText = Number.isFinite(deltaNorm) ? `${formatNumber(deltaNorm)} м` : '—'; + meta.textContent = `Время расчета: ${formatDateTime(response.time)}. |Δr| = ${deltaText}. Эпохи: TLE 1 — ${formatDateTime(response.firstEpoch)}, TLE 2 — ${formatDateTime(response.secondEpoch)}.`; } } @@ -114,16 +124,46 @@ } } + function updateTimeLimits() { + const input = el('tle-comparison-time'); + const helper = el('tle-comparison-time-helper'); + const minTime = maxEpoch(); + if (!input) return; + if (!minTime) { + input.removeAttribute('min'); + if (helper) helper.textContent = 'Минимальное допустимое время появится после разбора двух TLE.'; + return; + } + input.min = toDateTimeLocalValue(minTime); + if (!input.value || input.value < input.min) { + input.value = input.min; + } + if (helper) helper.textContent = `Минимальное допустимое время: ${formatDateTime(minTime)}.`; + } + + function validateCalculationTime() { + const input = el('tle-comparison-time'); + const minTime = maxEpoch(); + if (!input || !minTime || !input.value) return; + const time = getCalculationTime(); + if (time && time < minTime) { + showAlert(`Время расчета должно быть не раньше максимальной эпохи TLE: ${formatDateTime(minTime)}.`, 'warning'); + } + } + function clearPage() { el('tle-first-text').value = ''; el('tle-second-text').value = ''; + const time = el('tle-comparison-time'); + if (time) time.value = ''; state.first = null; state.second = null; updateReference('first', null); updateReference('second', null); + updateTimeLimits(); showAlert(''); - renderComparison([]); - setText('tle-comparison-result-meta', 'Нажмите “Сравнить” после ввода двух TLE.'); + renderComparison({ rows: [] }); + setText('tle-comparison-result-meta', 'Задайте время не раньше максимальной эпохи TLE и нажмите “Сравнить”.'); } async function postJson(url, payload) { @@ -145,6 +185,16 @@ return response.json(); } + function maxEpoch() { + if (!state.first?.time || !state.second?.time) return null; + return state.first.time >= state.second.time ? state.first.time : state.second.time; + } + + function getCalculationTime() { + const value = el('tle-comparison-time')?.value; + return value ? value : null; + } + function getTleText(side) { return el(`tle-${side}-text`)?.value || ''; } @@ -160,7 +210,7 @@ const button = el('tle-compare-submit'); if (!button) return; button.disabled = loading; - button.textContent = loading ? 'Сравнение...' : 'Сравнить'; + button.textContent = loading ? 'Расчет...' : 'Рассчитать'; } function showAlert(message, type = 'info') { @@ -174,11 +224,20 @@ : ''; } + function toDateTimeLocalValue(value) { + if (!value) return ''; + return String(value).slice(0, 19); + } + function formatDateTime(value) { if (!value) return ''; return String(value).replace('T', ' '); } + function formatNumber(value) { + return Number(value).toLocaleString('ru-RU', { maximumFractionDigits: 3 }); + } + function emptyToDash(value) { return value === null || value === undefined || value === '' ? '—' : value; } diff --git a/services/pcp-ui-service/src/main/resources/templates/tle-comparison.html b/services/pcp-ui-service/src/main/resources/templates/tle-comparison.html index 44e524c..ed9bfbd 100644 --- a/services/pcp-ui-service/src/main/resources/templates/tle-comparison.html +++ b/services/pcp-ui-service/src/main/resources/templates/tle-comparison.html @@ -13,10 +13,10 @@

Сравнение TLE

-
Вставьте два набора TLE, проверьте эпохи и сравните параметры, полученные через ballistics-service.
+
Вставьте два набора TLE, проверьте эпохи и рассчитайте положение спутника на заданный момент времени.
- +
@@ -26,9 +26,18 @@
Ввод данных
-
Можно вставить две или три строки TLE. Заголовок определяется автоматически, строки 1 и 2 обязательны.
+
Можно вставить две или три строки TLE. Заголовок определяется автоматически, строки 1 и 2 обязательны. Время расчета должно быть не раньше максимальной эпохи двух TLE.
+
+
+ + +
+
+
Минимальное допустимое время появится после разбора двух TLE.
+
+
@@ -90,11 +99,11 @@
Результаты
-
Нажмите “Сравнить” после ввода двух TLE.
+
Задайте время не раньше максимальной эпохи TLE и нажмите “Сравнить”.
-
Результаты сравнения появятся здесь.
+
Параметры положения и разность радиус-векторов появятся здесь.
@@ -102,7 +111,7 @@ - +
Параметр TLE 1 TLE 2РазницаРазница / значение