This commit is contained in:
Jake Kasper
2025-09-05 12:06:29 -04:00
parent 2b9a54b965
commit e1340a1e50
2 changed files with 49 additions and 21 deletions

View File

@@ -107,7 +107,13 @@ const sanitizePolygon = (coords) => {
} else { return [pts[0], pts[pts.length-1]]; }
};
try { filtered = rdp(filtered, EPS_DEG); } catch {}
return filtered;
// Ensure at least 3 unique points remain; if not, fall back to original coords
const unique = [];
for (const p of filtered) {
if (!unique.some(q => Math.abs(q[0]-p[0])<1e-9 && Math.abs(q[1]-p[1])<1e-9)) unique.push(p);
}
if (unique.length < 3) return coords;
return unique;
};
// @route GET /api/properties

View File

@@ -432,15 +432,18 @@ const PropertyDetail = () => {
// Convert backend sections to frontend format
if (propertyData.sections && propertyData.sections.length > 0) {
const convertedSections = propertyData.sections.map(section => ({
const convertedSections = propertyData.sections.map(section => {
const poly = typeof section.polygonData === 'string' ? JSON.parse(section.polygonData) : section.polygonData;
return {
id: section.id,
name: section.name,
coordinates: section.polygonData?.coordinates?.[0] || [],
color: section.polygonData?.color || SECTION_COLORS[0],
coordinates: poly?.coordinates?.[0] || [],
color: poly?.color || SECTION_COLORS[0],
area: section.area,
grassType: section.grassType || '',
grassTypes: section.grassTypes || null
}));
};
});
setLawnSections(convertedSections);
}
} catch (error) {
@@ -510,6 +513,16 @@ const PropertyDetail = () => {
return [avgLat, avgLng];
};
// Get the most accurate recent sample (prefer samples within 3s)
const bestRecentSample = () => {
const now = Date.now();
const recent = gpsSamples.filter(s => (now - (s.t || 0)) <= 3000);
const pool = (recent.length ? recent : gpsSamples).slice(-12);
if (pool.length === 0) return null;
const best = pool.reduce((b, s) => (s.accuracy < (b?.accuracy ?? Infinity) ? s : b), null);
return best ? [best.lat, best.lng, best.accuracy] : null;
};
const acceptAndNormalizePoint = (lat, lng, accuracy, currentPoints) => {
if (accuracy != null && accuracy > ACCURACY_MAX_METERS) {
toast("GPS accuracy too low (" + Math.round(accuracy) + "m). Waiting for better fix…");
@@ -546,16 +559,15 @@ const PropertyDetail = () => {
// GPS point collection (mark-at-location)
const markCurrentPoint = () => {
if (!navigator.geolocation) { toast.error('GPS not available'); return; }
navigator.geolocation.getCurrentPosition((pos) => {
const { latitude, longitude, accuracy } = pos.coords;
setGpsAccuracy(accuracy || null);
// Prefer most accurate recent fix from warm watch; fall back to immediate read
const candidate = bestRecentSample();
const useFix = (lat, lng, acc) => {
setGpsAccuracy(acc || null);
setGpsTracePoints(prev => {
const [sLat, sLng] = addSampleAndSmooth(latitude, longitude, accuracy);
const normalized = acceptAndNormalizePoint(sLat, sLng, accuracy, prev);
// For preview: check proximity to start even if skipping
const normalized = acceptAndNormalizePoint(lat, lng, acc, prev);
if (prev.length >= 2) {
const [slat, slng] = prev[0];
const dStart = haversine(slat, slng, sLat, sLng);
const dStart = haversine(slat, slng, lat, lng);
setIsSnapPreview(dStart <= SNAP_METERS);
} else { setIsSnapPreview(false); }
if (!normalized) return prev; // skip
@@ -566,10 +578,20 @@ const PropertyDetail = () => {
}
return next;
});
};
if (candidate) {
const [lat, lng, acc] = candidate;
useFix(lat, lng, acc);
} else {
navigator.geolocation.getCurrentPosition((pos) => {
const { latitude, longitude, accuracy } = pos.coords;
addSampleAndSmooth(latitude, longitude, accuracy);
useFix(latitude, longitude, accuracy);
}, (err)=>{
console.warn('GPS error', err?.message);
toast.error('GPS error: ' + (err?.message || 'unknown'));
}, { enableHighAccuracy: true, maximumAge: 1000, timeout: 10000 });
}, { enableHighAccuracy: true, maximumAge: 500, timeout: 8000 });
}
};
const undoLastPoint = () => {