From e1340a1e50dbb6e0420e18c251f64be5d259cb94 Mon Sep 17 00:00:00 2001 From: Jake Kasper Date: Fri, 5 Sep 2025 12:06:29 -0400 Subject: [PATCH] sadfasdf --- backend/src/routes/properties.js | 8 ++- .../src/pages/Properties/PropertyDetail.js | 62 +++++++++++++------ 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/backend/src/routes/properties.js b/backend/src/routes/properties.js index 495da4f..2b2c255 100644 --- a/backend/src/routes/properties.js +++ b/backend/src/routes/properties.js @@ -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 diff --git a/frontend/src/pages/Properties/PropertyDetail.js b/frontend/src/pages/Properties/PropertyDetail.js index 21224cf..796021d 100644 --- a/frontend/src/pages/Properties/PropertyDetail.js +++ b/frontend/src/pages/Properties/PropertyDetail.js @@ -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 => ({ - id: section.id, - name: section.name, - coordinates: section.polygonData?.coordinates?.[0] || [], - color: section.polygonData?.color || SECTION_COLORS[0], - area: section.area, - grassType: section.grassType || '', - grassTypes: section.grassTypes || null - })); + 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: 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; }); - }, (err)=>{ - console.warn('GPS error', err?.message); - toast.error('GPS error: ' + (err?.message || 'unknown')); - }, { enableHighAccuracy: true, maximumAge: 1000, timeout: 10000 }); + }; + 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: 500, timeout: 8000 }); + } }; const undoLastPoint = () => {