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]]; } } else { return [pts[0], pts[pts.length-1]]; }
}; };
try { filtered = rdp(filtered, EPS_DEG); } catch {} 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 // @route GET /api/properties

View File

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