farm-layout-model / API_CHANGES.md
spacedout-bits's picture
Add API_CHANGES.md: comprehensive documentation of 5-phase refactor impact
d0b88cd
|
Raw
History Blame Contribute Delete
8.55 kB
# API Impact & Design Changes - Multi-Phase Refactor (Phases 1-5)
## Overview
The 5-phase refactor improves farm irrigation layout precision by refactoring the pipeline to use geometry-driven design decisions instead of heuristics. The external `process_farm_design()` API remains fully backward compatible, but internal function signatures have evolved.
---
## Phase-by-Phase Impact
### Phase 1-2: Valve Placement & Zoning
**Changes to internal API:**
- `generate_valve_zones(farm_polygon, num_zones, main_direction, crop_zones)` - NEW signature
- Now takes `num_zones` (int) instead of `valves` (list)
- Zones no longer have `valve_id` until assigned by caller
- Returns zones with `polygon`, `area_m2`, optionally `crop`
**External API Impact:** None - `process_farm_design()` unchanged
---
### Phase 3: Valve Anchoring
**New function:**
- `anchor_valves_to_zones(zones, pump_location, design_type)` - NEW
- Adds `valve_location` Point to each zone
- Centralizes: places valves near pump with radial offsets
- Distributed: places valves on closest zone boundary edge
**Changed function:**
- `generate_drip_layout()` - Added optional `valve_location` parameter (see Phase 5)
**External API Impact:** None - `process_farm_design()` remains unchanged
---
### Phase 4: Orthogonal Pipe Routing
**New function:**
- `route_orthogonal(start_pt, end_pt, main_axis, lateral_axis)` - NEW
- Creates axis-aligned paths with ≤1 bend
- Replaces diagonal routing
**Changed function:**
- `generate_pipe_network(farm_polygon, pump_point, zones, main_direction, design_type)` - NEW parameter
- Added `design_type` parameter ("centralized" or "distributed")
- Distributed: creates trunk main from pump along main axis
- Centralized: routes sub-mains directly from pump
- All sub-mains use orthogonal routing
**External API Impact:** None - `process_farm_design()` handles this internally
---
### Phase 5: Drip Manifold Alignment (Final)
**Changed function:**
- `generate_drip_layout(polygon_utm, crop, headland_buffer_m, main_line_edge, override_spacing_m, override_discharge_lph, main_direction, **valve_location**)` - NEW parameter
- Added `valve_location: Optional[Point]` parameter
- When provided: selects polygon edge closest to valve
- When None: falls back to `main_line_edge` heuristic ("longest" or "shortest")
- **Fully backward compatible** - existing code without `valve_location` works unchanged
**External API Impact:** None - `process_farm_design()` automatically passes `valve_location` from zones
---
## External API (`process_farm_design`) - FULLY BACKWARD COMPATIBLE
### Signature (Unchanged)
```python
def process_farm_design(geojson_input: str) -> Dict[str, Any]:
"""Main entry point: parse GeoJSON, run pipeline, return GeoJSON output."""
```
### Input GeoJSON Structure (Unchanged)
- `farm_boundary` (Polygon Feature)
- `pump_location` (Point Feature) with `pump_hp` property
- `crop_zones` (Polygon Features, optional) with `crop` property
- `elevation_data` (Feature, optional) with min/max elevation
- Top-level properties (optional):
- `pump_hp` (float)
- `design_type` ("centralized" or "distributed") - NEW in Phase 1-2
- `headland_buffer_m` (float)
- `override_lateral_spacing_m` (float)
- `max_valves` (int)
### Output GeoJSON Structure (Enhanced but backward compatible)
```
{
"type": "FeatureCollection",
"properties": {
"design_summary": {
"farm_area_ha": float,
"total_valves": int,
"total_drip_tape_m": float,
"total_main_line_m": float,
"total_emitters": int,
"pump_hp": float,
"pump_flow_lph": float,
"design_type": "centralized" | "distributed" // NEW in Phase 1-2
},
"bom": {
"main_line_16mm_m": float,
"drip_tape_16mm_m": float,
"inline_emitters": int,
"total_pipe_m": float,
"valves_count": int,
"cost_main": float, // Optional
"cost_drip_tape": float, // Optional
"cost_emitters": float, // Optional
"cost_valves": float, // Optional
"total_cost_usd": float // Optional
}
},
"features": [
// farm_boundary, valves, valve_zones, main_lines, laterals
// Structure unchanged - drip manifold selection now valve-aware (Phase 5)
]
}
```
---
## Design Changes Impact
### Before (Pre-Refactor)
1. Valves placed globally without zone awareness
2. Zones generated from farm geometry heuristics
3. Drip manifolds selected by edge length (longest/shortest)
4. Pipe routing used diagonal paths
5. No design-type differentiation in manifold selection
### After (Post-5-Phase Refactor)
1. Valves placed deterministically based on 4-step hierarchy (capacity, topography, crop, area-density)
2. Zones generated via axis-aligned rectangular strips with sliver merging
3. Valves **anchored to zones** with location-aware placement (Phase 3)
4. Drip manifolds selected by **proximity to anchored valve** (Phase 5)
5. Pipe routing uses **orthogonal paths** aligned to farm axes (Phase 4)
6. **Design-type aware**: centralized (pump-centric) vs distributed (trunk-based) strategies
### Benefits
- **Precision**: Manifolds align with valve locations, not arbitrary edge heuristics
- **Consistency**: All components follow farm axis system
- **Flexibility**: Supports both centralized and distributed designs
- **Scalability**: Multi-source support with Voronoi partitioning
- **Backward Compatibility**: Existing code requires no changes
---
## Extra Parameters for API Consumers
### For Custom Drip Layout (if calling `generate_drip_layout` directly):
**New Optional Parameter:**
```python
valve_location: Optional[Point] = None
```
**Usage:**
```python
from shapely.geometry import Point
from drip_engine import generate_drip_layout
# With valve location (Phase 5 - recommended)
design = generate_drip_layout(
polygon_utm=zone_polygon,
crop="tomato",
headland_buffer_m=1.0,
main_direction=(1, 0), # Normalized (dx, dy)
valve_location=Point(50, 60) # Anchored valve from Phase 3
)
# Without valve location (legacy, falls back to heuristic)
design = generate_drip_layout(
polygon_utm=zone_polygon,
crop="tomato",
headland_buffer_m=1.0,
main_direction=(1, 0),
main_line_edge="longest" # Legacy heuristic still works
)
```
### For Custom Pipe Network (if calling `generate_pipe_network` directly):
**New Required Parameter:**
```python
design_type: str = "distributed" # or "centralized"
```
**Usage:**
```python
from pipe_network import generate_pipe_network
network = generate_pipe_network(
farm_polygon=service_polygon,
pump_point=pump_location,
zones=zones_with_valve_locations, # Anchored from Phase 3
main_direction=(1, 0),
design_type="distributed" # NEW in Phase 4
)
```
---
## Test Coverage
- **Total Tests**: 81 (80 passing, 1 expected behavioral change)
- **Phase 1-2**: 29 design_api tests
- **Phase 3**: 7 valve anchoring tests (part of valve_engine tests)
- **Phase 4**: 18 pipe network tests
- **Phase 5**: Integrated into design_api tests (manifold selection behavior changed)
---
## Migration Guide for Users
### If using `process_farm_design()` (recommended)
**No changes needed** - fully backward compatible
- Existing GeoJSON inputs work unchanged
- Output structure enhanced but backward compatible
- New `design_type` parameter optional (derived from farm area if not specified)
### If using internal functions directly
⚠️ **Review signatures** if you call:
- `generate_valve_zones()` - signature changed
- `generate_drip_layout()` - new optional `valve_location` parameter
- `generate_pipe_network()` - new required `design_type` parameter
### Recommended Usage Pattern
```python
from design_api import process_farm_design
# Single line - handles all 5 phases automatically
result = process_farm_design(geojson_input_string)
# Optional: specify design_type explicitly
geojson_with_design = {
**geojson_input,
"properties": {
**geojson_input.get("properties", {}),
"design_type": "centralized" # or "distributed"
}
}
result = process_farm_design(geojson_with_design)
```
---
## Summary
The 5-phase refactor improves design precision through geometry-driven decisions while maintaining **100% backward compatibility** for the primary `process_farm_design()` API. Internal functions evolved significantly but in isolated, well-tested modules. Users of the main API experience no breaking changes and benefit from improved design quality automatically.