You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
3.1 KiB
103 lines
3.1 KiB
import express from 'express';
|
|
import axios from 'axios';
|
|
import { getSentinelData, calculateNDVI, generateFieldPatternNDVI } from '../utils/sentinel.js';
|
|
|
|
const router = express.Router();
|
|
|
|
// Analyze field health
|
|
router.post('/analyze', async (req, res) => {
|
|
try {
|
|
const { polygon, date } = req.body;
|
|
|
|
if (!polygon || !polygon.coordinates) {
|
|
return res.status(400).json({ error: 'Polygon coordinates are required' });
|
|
}
|
|
|
|
console.log('Analyzing polygon:', polygon.coordinates[0].length, 'points');
|
|
|
|
// Получаем спутниковые данные
|
|
const satelliteData = await getSentinelData(polygon, date);
|
|
|
|
// Вычисляем NDVI
|
|
const ndviResult = await calculateNDVI(satelliteData);
|
|
|
|
// Генерируем статистику
|
|
const stats = generateNDVIStats(ndviResult.ndviValues);
|
|
|
|
// Для демонстрации используем сгенерированное изображение с паттернами
|
|
const demoImage = generateFieldPatternNDVI(400, 400);
|
|
|
|
res.json({
|
|
success: true,
|
|
data: {
|
|
ndviImage: demoImage, // Используем демо изображение
|
|
stats: stats,
|
|
date: satelliteData.date || new Date().toISOString().split('T')[0],
|
|
area: calculateArea(polygon),
|
|
polygon: polygon // Сохраняем полигон для истории
|
|
}
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error('Error in NDVI analysis:', error);
|
|
res.status(500).json({
|
|
error: 'Analysis failed',
|
|
message: error.message
|
|
});
|
|
}
|
|
});
|
|
|
|
// Остальные функции остаются без изменений...
|
|
// Generate NDVI statistics
|
|
function generateNDVIStats(ndviValues) {
|
|
const validValues = ndviValues.filter(v => !isNaN(v) && v >= -1 && v <= 1);
|
|
|
|
if (validValues.length === 0) {
|
|
return {
|
|
mean: 0,
|
|
min: 0,
|
|
max: 0,
|
|
healthy: 0,
|
|
moderate: 0,
|
|
poor: 0
|
|
};
|
|
}
|
|
|
|
const mean = validValues.reduce((a, b) => a + b, 0) / validValues.length;
|
|
const min = Math.min(...validValues);
|
|
const max = Math.max(...validValues);
|
|
|
|
// Categorize vegetation health
|
|
const healthy = validValues.filter(v => v > 0.6).length / validValues.length * 100;
|
|
const moderate = validValues.filter(v => v > 0.3 && v <= 0.6).length / validValues.length * 100;
|
|
const poor = validValues.filter(v => v <= 0.3).length / validValues.length * 100;
|
|
|
|
return {
|
|
mean: parseFloat(mean.toFixed(3)),
|
|
min: parseFloat(min.toFixed(3)),
|
|
max: parseFloat(max.toFixed(3)),
|
|
healthy: parseFloat(healthy.toFixed(1)),
|
|
moderate: parseFloat(moderate.toFixed(1)),
|
|
poor: parseFloat(poor.toFixed(1))
|
|
};
|
|
}
|
|
|
|
// Calculate area in hectares (simplified)
|
|
function calculateArea(polygon) {
|
|
const coords = polygon.coordinates[0];
|
|
let area = 0;
|
|
|
|
for (let i = 0; i < coords.length - 1; i++) {
|
|
const [x1, y1] = coords[i];
|
|
const [x2, y2] = coords[i + 1];
|
|
area += (x1 * y2 - x2 * y1);
|
|
}
|
|
|
|
area = Math.abs(area) / 2;
|
|
// Convert to hectares (approximate)
|
|
const areaHectares = area * 10000;
|
|
|
|
return parseFloat(areaHectares.toFixed(2));
|
|
}
|
|
|
|
export default router; |