generated from Grigo/AndroidTemplate
updated api
This commit is contained in:
@@ -1873,6 +1873,91 @@ function renderApiDebugViewshedLayer(geojson) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fitApiDebugLayer(layer) {
|
||||||
|
const bounds = layer?.getBounds?.();
|
||||||
|
if (bounds?.isValid?.()) {
|
||||||
|
setMapViewProgrammatically(() => map.fitBounds(bounds, { padding: [40, 40], maxZoom: 16 }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderApiDebugFresnelSlice(data) {
|
||||||
|
clearApiDebugCoverage();
|
||||||
|
clearApiDebugBeam();
|
||||||
|
const layers = [];
|
||||||
|
const pathLayer = data?.path_geojson ? L.geoJSON(data.path_geojson, {
|
||||||
|
style: { color: '#4fc3f7', weight: 3, opacity: 0.95 }
|
||||||
|
}) : null;
|
||||||
|
const fresnelLayer = data?.fresnel_geojson ? L.geoJSON(data.fresnel_geojson, {
|
||||||
|
style: {
|
||||||
|
color: '#ffd54f',
|
||||||
|
weight: 2,
|
||||||
|
opacity: 0.95,
|
||||||
|
fillColor: '#ffd54f',
|
||||||
|
fillOpacity: 0.2
|
||||||
|
}
|
||||||
|
}) : null;
|
||||||
|
const buildingsLayer = data?.buildings_geojson ? L.geoJSON(data.buildings_geojson, {
|
||||||
|
style: {
|
||||||
|
color: '#ff1744',
|
||||||
|
weight: 1.5,
|
||||||
|
opacity: 0.95,
|
||||||
|
fillColor: '#ff1744',
|
||||||
|
fillOpacity: 0.3
|
||||||
|
},
|
||||||
|
onEachFeature: (feature, layer) => {
|
||||||
|
const p = feature.properties || {};
|
||||||
|
const parts = [];
|
||||||
|
if (p.height_m != null) parts.push(`height ${fmtNum(p.height_m, 1, ' m')}`);
|
||||||
|
if (p.intersection_area_m2 != null) parts.push(`пересечение ${fmtNum(p.intersection_area_m2, 1, ' m²')}`);
|
||||||
|
if (p.building_type) parts.push(escapeHtml(p.building_type));
|
||||||
|
if (parts.length) layer.bindPopup(parts.join(' · '));
|
||||||
|
}
|
||||||
|
}) : null;
|
||||||
|
[fresnelLayer, buildingsLayer, pathLayer].forEach(layer => {
|
||||||
|
if (layer) layers.push(layer);
|
||||||
|
});
|
||||||
|
if (!layers.length) {
|
||||||
|
apiDebugSetSummary('Ответ fresnel-slice не содержит GeoJSON слоёв.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
apiDebugCoverageLayer = L.featureGroup(layers).addTo(map);
|
||||||
|
fitApiDebugLayer(apiDebugCoverageLayer);
|
||||||
|
const buildings = data?.buildings_geojson?.features?.length ?? 0;
|
||||||
|
const profilePoints = data?.profile?.length ?? 0;
|
||||||
|
apiDebugSetSummary(
|
||||||
|
`<b>Срез зоны Френеля:</b> ${profilePoints} точек профиля · ${buildings} зданий пересекают область<br>` +
|
||||||
|
`Жёлтая область — горизонтальный срез 60% зоны Френеля, красные полигоны — пересекающие здания.` +
|
||||||
|
formatDataSourcesLine(data?.data_sources)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderApiDebugBuildings(data) {
|
||||||
|
const features = data?.features?.length ?? 0;
|
||||||
|
const rendered = renderApiDebugGeoJsonLayer(data, {
|
||||||
|
style: {
|
||||||
|
color: '#ff1744',
|
||||||
|
weight: 1.3,
|
||||||
|
opacity: 0.95,
|
||||||
|
fillColor: '#ff1744',
|
||||||
|
fillOpacity: 0.22
|
||||||
|
},
|
||||||
|
onEachFeature: (feature, layer) => {
|
||||||
|
const p = feature.properties || {};
|
||||||
|
const parts = [];
|
||||||
|
if (p.height_m != null) parts.push(`height ${fmtNum(p.height_m, 1, ' m')}`);
|
||||||
|
if (p.levels != null) parts.push(`${p.levels} эт.`);
|
||||||
|
if (p.building_type) parts.push(escapeHtml(p.building_type));
|
||||||
|
if (p.source) parts.push(escapeHtml(p.source));
|
||||||
|
if (parts.length) layer.bindPopup(parts.join(' · '));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
apiDebugSetSummary(
|
||||||
|
rendered
|
||||||
|
? `<b>Здания вдоль линии:</b> ${features} объектов в буфере 50 m${formatDataSourcesLine(data?.data_sources)}`
|
||||||
|
: 'Ответ buildings/query не содержит GeoJSON features.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchApiDebugJobArtifact(jobId) {
|
async function fetchApiDebugJobArtifact(jobId) {
|
||||||
const f = apiDebugReadForm();
|
const f = apiDebugReadForm();
|
||||||
const url = `${f.base}/api/v1/jobs/${encodeURIComponent(jobId)}/artifact`;
|
const url = `${f.base}/api/v1/jobs/${encodeURIComponent(jobId)}/artifact`;
|
||||||
@@ -2221,6 +2306,23 @@ function buildApiDebugRequest(kind) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (kind === 'fresnelSlice') {
|
||||||
|
return {
|
||||||
|
method: 'POST',
|
||||||
|
path: '/api/v1/terrain/fresnel-slice',
|
||||||
|
body: {
|
||||||
|
tx,
|
||||||
|
rx,
|
||||||
|
frequency_mhz: f.frequency,
|
||||||
|
fresnel_fraction: 0.6,
|
||||||
|
include_buildings: true,
|
||||||
|
include_canopy: f.includeCanopy,
|
||||||
|
k_factor: 1.333,
|
||||||
|
samples: f.samples,
|
||||||
|
building_limit: 5000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
if (kind === 'budget') {
|
if (kind === 'budget') {
|
||||||
return {
|
return {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -2237,6 +2339,22 @@ function buildApiDebugRequest(kind) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (kind === 'buildings') {
|
||||||
|
return {
|
||||||
|
method: 'POST',
|
||||||
|
path: '/api/v1/buildings/query',
|
||||||
|
body: {
|
||||||
|
path: {
|
||||||
|
type: 'LineString',
|
||||||
|
coordinates: [
|
||||||
|
[f.tx.lon, f.tx.lat],
|
||||||
|
[f.rx.lon, f.rx.lat]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
buffer_m: 50
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
if (kind === 'landcover') {
|
if (kind === 'landcover') {
|
||||||
return {
|
return {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -2429,7 +2547,9 @@ async function runApiDebugDemo(kind) {
|
|||||||
}
|
}
|
||||||
if (kind === 'profile') renderApiDebugProfile(data, null, null);
|
if (kind === 'profile') renderApiDebugProfile(data, null, null);
|
||||||
else if (kind === 'los') renderApiDebugProfile(null, data, null);
|
else if (kind === 'los') renderApiDebugProfile(null, data, null);
|
||||||
|
else if (kind === 'fresnelSlice') renderApiDebugFresnelSlice(data);
|
||||||
else if (kind === 'budget') apiDebugSetSummary(formatApiDebugBudgetSummary(data));
|
else if (kind === 'budget') apiDebugSetSummary(formatApiDebugBudgetSummary(data));
|
||||||
|
else if (kind === 'buildings') renderApiDebugBuildings(data);
|
||||||
else if (kind === 'landcover') apiDebugSetSummary(formatApiDebugLandcoverSummary(data));
|
else if (kind === 'landcover') apiDebugSetSummary(formatApiDebugLandcoverSummary(data));
|
||||||
else if (kind === 'elevation') apiDebugSetSummary(formatApiDebugPointSummary(data));
|
else if (kind === 'elevation') apiDebugSetSummary(formatApiDebugPointSummary(data));
|
||||||
else if (kind === 'beam') renderApiDebugBeam(data);
|
else if (kind === 'beam') renderApiDebugBeam(data);
|
||||||
|
|||||||
@@ -71,7 +71,9 @@
|
|||||||
<button type="button" data-api-demo="elevation">Высота TX</button>
|
<button type="button" data-api-demo="elevation">Высота TX</button>
|
||||||
<button type="button" data-api-demo="profile">Только профиль</button>
|
<button type="button" data-api-demo="profile">Только профиль</button>
|
||||||
<button type="button" data-api-demo="los">Только LOS/Френель</button>
|
<button type="button" data-api-demo="los">Только LOS/Френель</button>
|
||||||
|
<button type="button" data-api-demo="fresnelSlice">Срез Френеля</button>
|
||||||
<button type="button" data-api-demo="budget">Только link budget</button>
|
<button type="button" data-api-demo="budget">Только link budget</button>
|
||||||
|
<button type="button" data-api-demo="buildings">Здания вдоль линии</button>
|
||||||
<button type="button" data-api-demo="landcover">Landcover path</button>
|
<button type="button" data-api-demo="landcover">Landcover path</button>
|
||||||
<button type="button" data-api-demo="beam">Сектор антенны</button>
|
<button type="button" data-api-demo="beam">Сектор антенны</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user