mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-23 00:26:36 +00:00
component decomposition is done
This commit is contained in:
@@ -0,0 +1,294 @@
|
||||
# Waypoint Validator
|
||||
|
||||
## Interface Definition
|
||||
|
||||
**Interface Name**: `IWaypointValidator`
|
||||
|
||||
### Interface Methods
|
||||
|
||||
```python
|
||||
class IWaypointValidator(ABC):
|
||||
@abstractmethod
|
||||
def validate_waypoint(self, waypoint: Waypoint) -> ValidationResult:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def validate_geofence(self, geofence: Geofences) -> ValidationResult:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def check_bounds(self, waypoint: Waypoint, geofences: Geofences) -> bool:
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def validate_route_continuity(self, waypoints: List[Waypoint]) -> ValidationResult:
|
||||
pass
|
||||
```
|
||||
|
||||
## Component Description
|
||||
|
||||
### Responsibilities
|
||||
- Validate individual waypoint data (GPS coordinates, altitude, confidence)
|
||||
- Validate geofence definitions (polygon bounds, topology)
|
||||
- Check waypoints against geofence boundaries
|
||||
- Validate route continuity (detect large gaps, validate sequencing)
|
||||
- Provide detailed validation error messages
|
||||
|
||||
### Scope
|
||||
- Input validation for Route API
|
||||
- Business rule enforcement (operational area restrictions for Ukraine)
|
||||
- Geospatial boundary checking
|
||||
- Data quality assurance
|
||||
|
||||
## API Methods
|
||||
|
||||
### `validate_waypoint(waypoint: Waypoint) -> ValidationResult`
|
||||
|
||||
**Description**: Validates a single waypoint's data integrity and constraints.
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API (before creating/updating)
|
||||
- R02 Route Data Manager (pre-persistence validation)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
Waypoint:
|
||||
id: str
|
||||
lat: float
|
||||
lon: float
|
||||
altitude: Optional[float]
|
||||
confidence: float
|
||||
timestamp: datetime
|
||||
refined: bool
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
ValidationResult:
|
||||
valid: bool
|
||||
errors: List[str]
|
||||
```
|
||||
|
||||
**Validation Rules**:
|
||||
1. **Latitude**: -90.0 <= lat <= 90.0
|
||||
2. **Longitude**: -180.0 <= lon <= 180.0
|
||||
3. **Altitude**: 0 <= altitude <= 1000 meters (if provided)
|
||||
4. **Confidence**: 0.0 <= confidence <= 1.0
|
||||
5. **Timestamp**: Not in future, not older than 1 year
|
||||
6. **Operational area** (Ukraine restriction): Latitude ~45-52N, Longitude ~22-40E
|
||||
7. **ID**: Non-empty string
|
||||
|
||||
**Error Conditions**:
|
||||
- Returns `ValidationResult` with `valid=False` and error list (not an exception)
|
||||
|
||||
**Test Cases**:
|
||||
1. **Valid waypoint**: All fields correct → returns `valid=True`
|
||||
2. **Invalid latitude**: lat=100 → returns `valid=False`, error="Latitude out of range"
|
||||
3. **Invalid longitude**: lon=200 → returns `valid=False`
|
||||
4. **Invalid confidence**: confidence=1.5 → returns `valid=False`
|
||||
5. **Future timestamp**: timestamp=tomorrow → returns `valid=False`
|
||||
6. **Outside operational area**: lat=10 (not Ukraine) → returns `valid=False`
|
||||
7. **Valid altitude**: altitude=500 → returns `valid=True`
|
||||
8. **Invalid altitude**: altitude=1500 → returns `valid=False`
|
||||
|
||||
---
|
||||
|
||||
### `validate_geofence(geofence: Geofences) -> ValidationResult`
|
||||
|
||||
**Description**: Validates geofence polygon definitions.
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API (during route creation)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
Geofences:
|
||||
polygons: List[Polygon]
|
||||
|
||||
Polygon:
|
||||
north_west: GPSPoint
|
||||
south_east: GPSPoint
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
ValidationResult:
|
||||
valid: bool
|
||||
errors: List[str]
|
||||
```
|
||||
|
||||
**Validation Rules**:
|
||||
1. **North-West corner**: NW.lat > SE.lat
|
||||
2. **North-West corner**: NW.lon < SE.lon (for Eastern Ukraine)
|
||||
3. **Polygon size**: Max 500km × 500km
|
||||
4. **Polygon count**: 1 <= len(polygons) <= 10
|
||||
5. **No self-intersection**: Polygons should not overlap
|
||||
6. **Within operational area**: All corners within Ukraine bounds
|
||||
|
||||
**Error Conditions**:
|
||||
- Returns `ValidationResult` with validation errors
|
||||
|
||||
**Test Cases**:
|
||||
1. **Valid geofence**: Single polygon in Ukraine → valid=True
|
||||
2. **Invalid corners**: NW.lat < SE.lat → valid=False
|
||||
3. **Too large**: 600km × 600km → valid=False
|
||||
4. **Too many polygons**: 15 polygons → valid=False
|
||||
5. **Overlapping polygons**: Two overlapping → valid=False (warning)
|
||||
|
||||
---
|
||||
|
||||
### `check_bounds(waypoint: Waypoint, geofences: Geofences) -> bool`
|
||||
|
||||
**Description**: Checks if a waypoint falls within geofence boundaries.
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API (optional check during waypoint updates)
|
||||
- R02 Route Data Manager (business rule enforcement)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
waypoint: Waypoint
|
||||
geofences: Geofences
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
bool: True if waypoint is within any geofence polygon
|
||||
```
|
||||
|
||||
**Algorithm**:
|
||||
- Point-in-polygon test for each geofence polygon
|
||||
- Returns True if point is inside at least one polygon
|
||||
|
||||
**Error Conditions**:
|
||||
- None (returns False if outside all geofences)
|
||||
|
||||
**Test Cases**:
|
||||
1. **Inside geofence**: Waypoint in polygon center → returns True
|
||||
2. **Outside geofence**: Waypoint 10km outside → returns False
|
||||
3. **On boundary**: Waypoint on polygon edge → returns True
|
||||
4. **Multiple geofences**: Waypoint in second polygon → returns True
|
||||
|
||||
---
|
||||
|
||||
### `validate_route_continuity(waypoints: List[Waypoint]) -> ValidationResult`
|
||||
|
||||
**Description**: Validates route continuity, detecting large gaps and sequence issues.
|
||||
|
||||
**Called By**:
|
||||
- R01 Route REST API (during route creation)
|
||||
- R02 Route Data Manager (route quality check)
|
||||
|
||||
**Input**:
|
||||
```python
|
||||
waypoints: List[Waypoint] # Should be ordered by sequence/timestamp
|
||||
```
|
||||
|
||||
**Output**:
|
||||
```python
|
||||
ValidationResult:
|
||||
valid: bool
|
||||
errors: List[str]
|
||||
warnings: List[str]
|
||||
```
|
||||
|
||||
**Validation Rules**:
|
||||
1. **Minimum waypoints**: len(waypoints) >= 2
|
||||
2. **Maximum waypoints**: len(waypoints) <= 3000
|
||||
3. **Timestamp ordering**: waypoints[i].timestamp < waypoints[i+1].timestamp
|
||||
4. **Distance gaps**: Consecutive waypoints < 500 meters apart (warning if violated)
|
||||
5. **Large gap detection**: Flag gaps > 1km (warning for potential data loss)
|
||||
6. **No duplicate timestamps**: All timestamps unique
|
||||
|
||||
**Error Conditions**:
|
||||
- Returns `ValidationResult` with errors and warnings
|
||||
|
||||
**Test Cases**:
|
||||
1. **Valid route**: 100 waypoints, 100m spacing → valid=True
|
||||
2. **Too few waypoints**: 1 waypoint → valid=False
|
||||
3. **Too many waypoints**: 3500 waypoints → valid=False
|
||||
4. **Unordered timestamps**: waypoints out of order → valid=False
|
||||
5. **Large gap**: 2km gap between waypoints → valid=True with warning
|
||||
6. **Duplicate timestamps**: Two waypoints same time → valid=False
|
||||
|
||||
## Integration Tests
|
||||
|
||||
### Test 1: Complete Validation Pipeline
|
||||
1. Create waypoint with all valid data
|
||||
2. validate_waypoint() → passes
|
||||
3. Create geofence for Eastern Ukraine
|
||||
4. validate_geofence() → passes
|
||||
5. check_bounds() → waypoint inside geofence
|
||||
|
||||
### Test 2: Route Validation Flow
|
||||
1. Create 500 waypoints with 100m spacing
|
||||
2. validate_route_continuity() → passes
|
||||
3. Add waypoint 2km away
|
||||
4. validate_route_continuity() → passes with warning
|
||||
5. Add waypoint with past timestamp
|
||||
6. validate_route_continuity() → fails
|
||||
|
||||
### Test 3: Edge Cases
|
||||
1. Waypoint on geofence boundary
|
||||
2. Waypoint at North Pole (lat=90)
|
||||
3. Waypoint at dateline (lon=180)
|
||||
4. Route with exactly 3000 waypoints
|
||||
|
||||
## Non-Functional Requirements
|
||||
|
||||
### Performance
|
||||
- **validate_waypoint**: < 1ms per waypoint
|
||||
- **validate_geofence**: < 10ms per geofence
|
||||
- **check_bounds**: < 2ms per check
|
||||
- **validate_route_continuity**: < 100ms for 2000 waypoints
|
||||
|
||||
### Accuracy
|
||||
- GPS coordinate validation: 6 decimal places precision (0.1m)
|
||||
- Geofence boundary check: 1-meter precision
|
||||
|
||||
### Maintainability
|
||||
- Validation rules configurable via configuration file
|
||||
- Easy to add new validation rules
|
||||
- Clear error messages for debugging
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Internal Components
|
||||
- **R04 Route Database Layer**: For loading existing route data (optional context)
|
||||
- **H06 Web Mercator Utils**: For distance calculations (optional)
|
||||
|
||||
### External Dependencies
|
||||
- **Shapely** (optional): For advanced polygon operations
|
||||
- **Geopy**: For geodesic distance calculations
|
||||
|
||||
## Data Models
|
||||
|
||||
### ValidationResult
|
||||
```python
|
||||
class ValidationResult(BaseModel):
|
||||
valid: bool
|
||||
errors: List[str] = []
|
||||
warnings: List[str] = []
|
||||
```
|
||||
|
||||
### OperationalArea (Configuration)
|
||||
```python
|
||||
class OperationalArea(BaseModel):
|
||||
name: str = "Eastern Ukraine"
|
||||
min_lat: float = 45.0
|
||||
max_lat: float = 52.0
|
||||
min_lon: float = 22.0
|
||||
max_lon: float = 40.0
|
||||
```
|
||||
|
||||
### ValidationRules (Configuration)
|
||||
```python
|
||||
class ValidationRules(BaseModel):
|
||||
max_altitude: float = 1000.0 # meters
|
||||
max_waypoint_gap: float = 500.0 # meters
|
||||
max_route_waypoints: int = 3000
|
||||
min_route_waypoints: int = 2
|
||||
max_geofence_size: float = 500000.0 # meters (500km)
|
||||
max_geofences: int = 10
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user