spreader
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import * as turf from '@turf/turf';
|
||||
import { applicationsAPI } from '../../services/api';
|
||||
import PropertyMap from '../Maps/PropertyMap';
|
||||
import { XMarkIcon, ClockIcon, MapPinIcon, WrenchScrewdriverIcon, BeakerIcon } from '@heroicons/react/24/outline';
|
||||
@@ -44,21 +45,67 @@ const ApplicationViewModal = ({ application, propertyDetails, onClose }) => {
|
||||
const calculateCoverage = (application, log) => {
|
||||
if (!log?.gpsTrack?.points || log.gpsTrack.points.length < 2) return 0;
|
||||
|
||||
const totalDistanceFeet = distanceFeet(log);
|
||||
const plannedArea = application.totalSectionArea || 0;
|
||||
if (totalDistanceFeet === 0 || plannedArea === 0) return 0;
|
||||
|
||||
// Estimate equipment width based on type (feet)
|
||||
let equipmentWidth = 4;
|
||||
// Determine equipment width (feet)
|
||||
let widthFeet = 4;
|
||||
const equipmentFromPlan = planDetails?.equipment || {};
|
||||
if (typeof equipmentFromPlan.spreadWidth === 'number' && equipmentFromPlan.spreadWidth > 0) {
|
||||
widthFeet = equipmentFromPlan.spreadWidth;
|
||||
} else if (typeof equipmentFromPlan.sprayWidthFeet === 'number' && equipmentFromPlan.sprayWidthFeet > 0) {
|
||||
widthFeet = equipmentFromPlan.sprayWidthFeet;
|
||||
} else {
|
||||
const equipmentName = application.equipmentName?.toLowerCase() || '';
|
||||
if (equipmentName.includes('spreader')) equipmentWidth = 12;
|
||||
else if (equipmentName.includes('sprayer')) equipmentWidth = 20;
|
||||
else if (equipmentName.includes('mower')) equipmentWidth = 6;
|
||||
if (equipmentName.includes('spreader')) widthFeet = 12;
|
||||
else if (equipmentName.includes('sprayer')) widthFeet = 20;
|
||||
else if (equipmentName.includes('mower')) widthFeet = 6;
|
||||
}
|
||||
|
||||
// Distance (ft) * Width (ft) = Area (sq ft)
|
||||
const theoreticalCoverageArea = totalDistanceFeet * equipmentWidth;
|
||||
const coveragePercentage = Math.min((theoreticalCoverageArea / plannedArea) * 100, 100);
|
||||
return Math.round(coveragePercentage);
|
||||
const plannedAreaSqFt = application.totalSectionArea || 0;
|
||||
if (plannedAreaSqFt <= 0) return 0;
|
||||
|
||||
// Build union polygon of all planned sections
|
||||
try {
|
||||
const polygons = (sections || []).map((section) => {
|
||||
let poly = section.polygonData;
|
||||
if (typeof poly === 'string') {
|
||||
try { poly = JSON.parse(poly); } catch { poly = null; }
|
||||
}
|
||||
if (!poly?.coordinates?.[0]) return null;
|
||||
// Convert [lat,lng] -> [lng,lat]
|
||||
const coords = poly.coordinates[0].map(([lat, lng]) => [lng, lat]);
|
||||
return turf.polygon([coords]);
|
||||
}).filter(Boolean);
|
||||
|
||||
if (polygons.length === 0) {
|
||||
// Fallback: distance * width heuristic
|
||||
const totalDistanceFeet = distanceFeet(log);
|
||||
if (totalDistanceFeet === 0) return 0;
|
||||
const areaFt2 = totalDistanceFeet * widthFeet;
|
||||
return Math.min(Math.round((areaFt2 / plannedAreaSqFt) * 100), 100);
|
||||
}
|
||||
|
||||
const plannedUnion = polygons.reduce((acc, cur) => acc ? turf.union(acc, cur) : cur, null);
|
||||
if (!plannedUnion) return 0;
|
||||
|
||||
// Buffer the GPS line by half the width
|
||||
const lineCoords = log.gpsTrack.points.map((p) => [p.lng, p.lat]);
|
||||
const line = turf.lineString(lineCoords);
|
||||
const bufferKm = (widthFeet / 2) * 0.3048 / 1000; // feet -> meters -> km
|
||||
const swath = turf.buffer(line, bufferKm, { units: 'kilometers' });
|
||||
if (!swath) return 0;
|
||||
|
||||
const overlap = turf.intersect(swath, plannedUnion);
|
||||
if (!overlap) return 0;
|
||||
|
||||
const overlapSqMeters = turf.area(overlap);
|
||||
const plannedSqMeters = plannedAreaSqFt * 0.092903;
|
||||
const pct = (overlapSqMeters / plannedSqMeters) * 100;
|
||||
return Math.min(Math.round(pct), 100);
|
||||
} catch (e) {
|
||||
console.warn('Coverage calc fallback due to error:', e);
|
||||
const totalDistanceFeet = distanceFeet(log);
|
||||
const areaFt2 = totalDistanceFeet * widthFeet;
|
||||
return Math.min(Math.round((areaFt2 / plannedAreaSqFt) * 100), 100);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user