-
Notifications
You must be signed in to change notification settings - Fork 0
Feat/instant usage v1 #22
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v4
Are you sure you want to change the base?
Changes from all commits
a761f96
41d5131
40fd8d5
3b85d69
fa18190
aa97551
4b00930
eb917f2
7076c8d
94011cc
c9f0d14
e6e636b
625f13d
18b03d2
c6d2d14
0789cd9
0906847
055fc1e
db25863
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,122 @@ | ||
| # Feature Specification: Instant Usage (0-1 Point Calibration) | ||
|
|
||
| ## 1. Overview | ||
| The "Instant Usage" feature aims to provide immediate value to the user after importing a map, even before they have provided the minimum required two GPS reference points. By making sensible assumptions (perfect top down view and North is up) and only asking the user to provide a reference scale, the app can enable the measurement tool and live position tracking earlier in the workflow. | ||
|
|
||
| ## 2. Functional Requirements | ||
|
|
||
| ### 2.1 Zero GPS Points | ||
| * **Measurement Tool**: Enabled if a manual `referenceDistance` (Set Scale) has been provided. | ||
| * **Live Position**: Disabled. | ||
|
|
||
| ### 2.2 One GPS Point | ||
| * **Measurement Tool**: Enabled if a manual `referenceDistance` has been provided. | ||
| * **Live Position**: **Enabled** if a manual `referenceDistance` has been provided, using a fallback calibration. | ||
| * **Fallback Calibration (1-Point Similarity)**: | ||
| * **Translation**: Fixed by the single GPS reference point. | ||
| * **Rotation**: Assumed to be **0° (North is Up)**. | ||
| * **Scale**: Use `referenceDistance.metersPerPixel`. | ||
| * **User Feedback**: Display a banner/toast: *"Using 1-point calibration (North-up). Add a second point to fix orientation and scale."* | ||
|
|
||
| ### 2.3 Two+ GPS Points | ||
| * **Standard Calibration**: Use the existing robust Similarity/Affine/Homography pipeline. | ||
| * **Scale Harmonization**: If a manual `referenceDistance` is provided, it can be used to constrain the Similarity fit (Phase 2). | ||
|
|
||
| ### 2.4 Quick Start Flow | ||
| 1. **Import Map**: User selects an image (of a map or floorplan). | ||
| 2. Ask the user to provide a reference scale so that once he did provide that reference scale he can measure any distances on the image | ||
| 3. **Initial Suggestion**: App asks: "Are you on currently on this map? If yes where". | ||
| 1. **One-Tap Calibration**: If user says yes ask him to tap their current location on the photo. | ||
| 2. **Immediate Live View**: The app immediately starts showing the live GPS position on the photo using the 1-point fallback. | ||
| 3. **Refinement**: As the user moves, they can see if the dot follows the map. If not, they add a second point to "pin" the scale and rotation. | ||
|
|
||
|
|
||
| ## 3. Technical Implementation | ||
|
|
||
| ### 3.1 Math Layer (`src/geo/transformations.js`) | ||
| Implement `fitSimilarity1Point(pair, scale, rotation)` which returns a standard transform object. | ||
|
|
||
| ```javascript | ||
| /** | ||
| * Creates a similarity transform from a single point, scale, and rotation. | ||
| * @param {Object} pair - { pixel: {x, y}, enu: {x, y} } | ||
| * @param {number} scale - Meters per pixel | ||
| * @param {number} [rotation=0] - Rotation in radians (0 = North is Up) | ||
| */ | ||
| export function fitSimilarity1Point(pair, scale, rotation = 0) { | ||
| const cos = Math.cos(rotation); | ||
| const sin = Math.sin(rotation); | ||
|
|
||
| // Matrix: [m00, m01, m10, m11, tx, ty] | ||
| // enu.x = m00 * px + m10 * py + tx | ||
| // enu.y = m01 * px + m11 * py + ty | ||
| const m00 = scale * cos; | ||
| const m01 = scale * sin; | ||
| const m10 = -scale * sin; | ||
| const m11 = scale * cos; | ||
|
|
||
| const tx = pair.enu.x - (m00 * pair.pixel.x + m10 * pair.pixel.y); | ||
| const ty = pair.enu.y - (m01 * pair.pixel.x + m11 * pair.pixel.y); | ||
|
|
||
| return { | ||
| matrix: [m00, m01, m10, m11, tx, ty], | ||
| kind: 'similarity', | ||
| rmse: 0, | ||
| maxResidual: 0, | ||
| inliers: [pair], | ||
| }; | ||
| } | ||
| ``` | ||
|
|
||
| ### 3.2 Calibration Layer (`src/calibration/calibrator.js`) | ||
| Update `calibrateMap` to handle the 1-point case. | ||
|
|
||
| ```javascript | ||
| function calibrateMap(pairs, userOptions = {}) { | ||
| // ... | ||
| if (pairs.length === 1) { | ||
| const scale = userOptions.referenceScale; | ||
| if (!scale) return null; // Cannot calibrate 1-point without scale | ||
| const rotation = userOptions.defaultRotation || 0; | ||
| const model = fitSimilarity1Point(enrichedPairs[0], scale, rotation); | ||
| return { ...model, origin, pairs: enrichedPairs }; | ||
| } | ||
| // ... | ||
| } | ||
| ``` | ||
|
Comment on lines
+39
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code snippets for
To avoid confusion for future developers, it would be beneficial to update these snippets to accurately reflect the implemented code. |
||
|
|
||
| ### 3.3 UI Layer (`src/index.js`) | ||
| * **Post-Import Prompt**: Immediately after map import (no scale is set yet), display a prominent "Set Scale" button. | ||
| * **Location Prompt**: In parallel show a button *"Are you currently on this map?"* | ||
| * If Clicked, enter **One-Tap Calibration** mode. | ||
| * **One-Tap Calibration UI**: | ||
| * When active, the next tap on the photo captures the current GPS position (waiting for accuracy if needed) and creates a single reference pair. | ||
| * Automatically trigger `calibrateMap()` and enable "Live" mode. | ||
| * **Fallback Indicator**: | ||
| * When `state.pairs.length === 1`, show a status badge: "1-Point Calibration (North-up)". | ||
| * **Live Button**: Enable when `state.pairs.length >= 1` AND a manual scale is set. | ||
| * **Settings**: Add a "Default Rotation" (default: 0°). | ||
|
|
||
| ## 4. Edge Cases & Considerations | ||
| * **Unstable 2-Point Fit**: If two GPS points are extremely close together, the rotation becomes numerically unstable. In this case, the system should either warn the user or offer to stick to the "North-up" assumption. | ||
| * **Missing Scale**: If the user provides 1 GPS point but hasn't set a scale yet, the "Live" mode remains disabled until the scale is defined (either because the user later decided to set the reference scale or because he decided to set a second gps reference point). | ||
|
|
||
| ## 5. Development Progress Notes | ||
|
|
||
| ### Phase 1: Math & Logic (Completed) | ||
| - **1-Point Similarity**: Implemented `fitSimilarity1Point` in [src/geo/transformations.js](src/geo/transformations.js). It creates a transform from a single point, a fixed scale, and an assumed 0° rotation. | ||
| - **Fixed-Scale Similarity**: Implemented `fitSimilarityFixedScale` to allow 2+ point calibration while constraining the scale to a manual reference value. | ||
| - **Calibrator Update**: Updated `calibrateMap` in [src/calibration/calibrator.js](src/calibration/calibrator.js) to support the 1-point fallback when `referenceScale` is provided. | ||
|
|
||
| ### Phase 2: UI Integration (Completed) | ||
| - **Quick Start Prompts**: Added a dedicated prompt area in [index.html](index.html) that appears immediately after map import. | ||
| - **One-Tap Calibration**: Implemented `startOneTapMode` and `handleOneTapClick` in [src/index.js](src/index.js). This allows users to "pin" their current GPS location to a spot on the photo with a single tap. | ||
| - **Scale & Measure Modes**: Integrated the state machine from [src/scale/scale-mode.js](src/scale/scale-mode.js) to handle "Set Scale" and "Measure" interactions. | ||
| - **Persistence**: Manual scale and preferred units are now persisted in `localStorage`. | ||
|
|
||
| ### Phase 3: Quality & Validation (Completed) | ||
| - **Unit Tests**: Added comprehensive tests for 1-point and fixed-scale transformations in [src/geo/transformations.test.js](src/geo/transformations.test.js). | ||
| - **Integration Tests**: Created [src/index.scale.test.js](src/index.scale.test.js) to verify the end-to-end "Instant Usage" flow, including prompt visibility and one-tap calibration. | ||
| - **Complexity Management**: Refactored `updateStatusText`, `recalculateCalibration`, and `setupEventHandlers` in [src/index.js](src/index.js) to keep cyclomatic complexity within limits (<= 10). | ||
| - **Coverage**: Maintained >99% statement coverage across all modified files. | ||
| - **Validation**: Verified all quality checks (`lint`, `check:dup`, `check:cycles`, `check:boundaries`) pass successfully. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This section of the 'Quick Start Flow' has a few areas that could be improved for clarity and professionalism:
theminstead ofhim) is a best practice.