fixed referrence

This commit is contained in:
2026-06-26 12:30:03 +03:00
parent 85de7a5ca9
commit ff1d3b17c1
2 changed files with 46 additions and 13 deletions
+33 -7
View File
@@ -2283,6 +2283,7 @@ function apiDebugReadForm() {
samples: Math.max(2, Math.min(2048, Math.round(apiDebugNumber('apiDebugSamples', 128)))),
model: document.getElementById('apiDebugModel')?.value || 'manual',
coverageModel: document.getElementById('apiDebugCoverageModel')?.value || 'itm',
coverageFormat: document.getElementById('apiDebugCoverageFormat')?.value || 'geojson',
includeCanopy: !!document.getElementById('apiDebugIncludeCanopy')?.checked
};
}
@@ -2431,6 +2432,25 @@ function renderApiDebugCoverageLayer(geojson, model) {
return { rendered, levels };
}
function formatApiDebugCoverageRasterSummary(job, data) {
const meta = data?.metadata || {};
const jobId = job?.jobId || '—';
const format = data?.format || job?.result?.format || meta.format || '—';
const artifactPath = `/api/v1/jobs/${encodeURIComponent(jobId)}/artifact`;
const artifactUrl = `${apiDebugReadForm().base}${artifactPath}`;
const stats = [
`resolution ${fmtNum(meta.resolution_m, 0, ' m')}`,
`${meta.width ?? '—'}×${meta.height ?? '—'}`,
`valid ${meta.valid_pixels ?? '—'} px`,
`min ${fmtNum(meta.min_dbm, 1, ' dBm')}`,
`max ${fmtNum(meta.max_dbm, 1, ' dBm')}`
].join(' · ');
return `<b>Coverage raster:</b> ${escapeHtml(format)} · model ${escapeHtml(job?.result?.model || '—')}<br>` +
`${stats}<br>` +
`<b>Файл:</b> ${escapeHtml(data?.uri || '—')}<br>` +
`<b>Скачать через proxy:</b> <a href="${escapeHtml(artifactUrl)}" target="_blank" rel="noopener">artifact</a>`;
}
function renderApiDebugViewshedLayer(geojson) {
return renderApiDebugGeoJsonLayer(geojson, {
style: {
@@ -2980,9 +3000,10 @@ function buildApiDebugRequest(kind) {
azimuth_step_deg: 2,
range_step_m: 50,
include_buildings: true,
include_canopy: f.includeCanopy,
include_vegetation: false,
levels_dbm: [-90, -100, -110],
format: 'geojson'
format: f.coverageFormat
}
};
}
@@ -3069,12 +3090,16 @@ async function runApiDebugDemo(kind) {
return;
}
if (kind === 'coverage') {
const geojson = job.result?.data;
const coverageData = job.result?.data;
const model = job.result?.model || apiDebugReadForm().coverageModel;
const { rendered, levels } = renderApiDebugCoverageLayer(geojson, model);
const features = geojson?.features?.length ?? 0;
if (coverageData?.kind === 'coverage_raster') {
apiDebugSetSummary(formatApiDebugCoverageRasterSummary(job, coverageData));
return;
}
const { rendered, levels } = renderApiDebugCoverageLayer(coverageData, model);
const features = coverageData?.features?.length ?? 0;
const fsplHint = model === 'fspl'
? '<br><span class="api-debug-mini">FSPL + omni = идеальный круг (рельеф не учитывается). Для формы по местности — ITM.</span>'
? '<br><span class="api-debug-mini">FSPL + omni без surface obstruction даёт круг; сейчас API добавляет buildings/canopy loss, если включены соответствующие флаги.</span>'
: '';
if (rendered) {
apiDebugSetSummary(
@@ -3287,8 +3312,9 @@ function formatApiDebugBudgetSummary(budget) {
return `<b>Link budget (${escapeHtml(model)}):</b> энергетически проходит ${fmtBool(budget.link_viable)} · margin ${fmtNum(budget.fade_margin_db, 1, ' dB')}<br>` +
`<b>Зона Френеля:</b> ${escapeHtml(quality)} · clear ${fmtBool(budget.fresnel_clear)}<br>` +
`<b>RX power:</b> ${fmtNum(budget.rx_power_dbm, 1, ' dBm')} · total loss ${fmtNum(budget.total_loss_db, 1, ' dB')}<br>` +
`<b>FSPL:</b> ${fmtNum(budget.fspl_db, 1, ' dB')} · diffraction ${fmtNum(budget.diffraction_db, 1, ' dB')} · ` +
`vegetation ${fmtNum(budget.vegetation_db, 1, ' dB')} · atmospheric ${fmtNum(budget.atmospheric_db, 1, ' dB')}` +
`<b>Loss:</b> FSPL ${fmtNum(budget.fspl_db, 1, ' dB')} · active excess ${fmtNum(budget.propagation_excess_db ?? budget.diffraction_db, 1, ' dB')} · ` +
`knife-edge ${fmtNum(budget.knife_edge_diffraction_db, 1, ' dB')}<br>` +
`<b>Environment:</b> vegetation ${fmtNum(budget.vegetation_db, 1, ' dB')} · atmospheric ${fmtNum(budget.atmospheric_db, 1, ' dB')}` +
formatDataSourcesLine(budget.data_sources);
}
+9 -2
View File
@@ -50,7 +50,7 @@
<option value="p452">p452</option>
</select>
</label>
<label class="api-debug-check"><input type="checkbox" id="apiDebugIncludeCanopy" />canopy в профиле</label>
<label class="api-debug-check"><input type="checkbox" id="apiDebugIncludeCanopy" />canopy (если уже загружен)</label>
</div>
<div class="api-debug-section">
<div class="api-debug-section-title">1. Выбор точек</div>
@@ -80,7 +80,7 @@
</div>
<div class="api-debug-section">
<div class="api-debug-section-title">3. Async jobs (Celery)</div>
<div class="api-debug-help">Viewshed и coverage ставятся в очередь; UI опрашивает <code>/api/v1/jobs/{id}</code> и подгружает GeoJSON артефакт. Coverage с <b>FSPL</b> даёт круг (без рельефа) — для реалистичного контура выберите <b>ITM</b>.</div>
<div class="api-debug-help">Viewshed и coverage ставятся в очередь; UI опрашивает <code>/api/v1/jobs/{id}</code>. Coverage умеет GeoJSON/PNG/GeoTIFF; canopy включайте только когда данные уже загружены.</div>
<div class="api-debug-grid" style="margin-top:6px">
<label>Модель coverage
<select id="apiDebugCoverageModel">
@@ -89,6 +89,13 @@
<option value="p1812">p1812</option>
</select>
</label>
<label>Формат coverage
<select id="apiDebugCoverageFormat">
<option value="geojson" selected>geojson</option>
<option value="png">png raster</option>
<option value="geotiff">geotiff raster</option>
</select>
</label>
</div>
<div class="api-debug-actions">
<button type="button" data-api-demo="viewshed">Viewshed</button>