|
12 | 12 | Supports multiple AOIs and multiple date ranges. |
13 | 13 | """ |
14 | 14 |
|
15 | | -import os |
| 15 | +# client.py |
16 | 16 | import logging |
17 | | -from typing import List |
| 17 | +from typing import List, Optional, Tuple |
| 18 | +from planet_overlap.filters import build_filters |
| 19 | +from planet_overlap.geometry import load_aoi |
18 | 20 |
|
19 | | -from planet_overlap import filters, pagination, analysis, geometry |
| 21 | +logging.basicConfig(level=logging.INFO) |
20 | 22 |
|
21 | | -# Configure logging for progress tracking |
22 | | -logging.basicConfig( |
23 | | - level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s" |
24 | | -) |
25 | 23 |
|
26 | | - |
27 | | -def run_client( |
28 | | - aoi_files: List[str], |
29 | | - start_dates: List[str], |
30 | | - end_dates: List[str], |
31 | | - output_dir: str = "./outputs", |
32 | | - cloud_max: float = 0.5, |
33 | | - min_sun_angle: float = 0.0, |
34 | | - spatial_tile_threshold_km2: float = 10000, |
35 | | - temporal_tile_threshold_days: int = 30, |
36 | | -) -> None: |
| 24 | +def prepare_filters( |
| 25 | + geojson_paths: List[str], |
| 26 | + date_ranges: List[Tuple[str, str]] |
| 27 | +) -> dict: |
37 | 28 | """ |
38 | | - Main function to execute Planet Overlap workflow. |
39 | | -
|
40 | | - Parameters |
41 | | - ---------- |
42 | | - aoi_files : List[str] |
43 | | - Paths to one or more AOI GeoJSON files. |
44 | | - start_dates : List[str] |
45 | | - Start dates corresponding to each AOI (format 'YYYY-MM-DD'). |
46 | | - end_dates : List[str] |
47 | | - End dates corresponding to each AOI (format 'YYYY-MM-DD'). |
48 | | - output_dir : str |
49 | | - Directory where output files will be saved. |
50 | | - cloud_max : float |
51 | | - Maximum cloud cover allowed (0-1). |
52 | | - min_sun_angle : float |
53 | | - Minimum sun angle allowed in degrees. |
54 | | - spatial_tile_threshold_km2 : float |
55 | | - Max AOI area before spatial tiling is applied. |
56 | | - temporal_tile_threshold_days : int |
57 | | - Max date range before temporal tiling is applied. |
| 29 | + Build filters for multiple AOIs and date ranges. |
| 30 | + |
| 31 | + Args: |
| 32 | + geojson_paths: List of file paths to AOI geojsons. |
| 33 | + date_ranges: List of (start_date, end_date) tuples. |
| 34 | + |
| 35 | + Returns: |
| 36 | + Dictionary containing combined filters. |
58 | 37 | """ |
| 38 | + filters = build_filters(geojson_paths, date_ranges) |
| 39 | + logging.info("Filters prepared for %d AOIs/date ranges", len(filters.get("config", []))) |
| 40 | + return filters |
59 | 41 |
|
60 | | - if not os.path.exists(output_dir): |
61 | | - os.makedirs(output_dir) |
62 | | - logging.info(f"Created output directory: {output_dir}") |
63 | | - |
64 | | - # Read and buffer AOIs |
65 | | - logging.info("Reading AOIs...") |
66 | | - aois = [] |
67 | | - for file in aoi_files: |
68 | | - try: |
69 | | - aoi_geom = geometry.read_geojson(file) |
70 | | - buffered_aoi = geometry.buffer_points(aoi_geom) |
71 | | - aois.append(buffered_aoi) |
72 | | - except Exception as e: |
73 | | - logging.error(f"Failed to read or buffer AOI {file}: {e}") |
74 | | - continue |
75 | | - |
76 | | - # Loop through each AOI and date range |
77 | | - for i, aoi in enumerate(aois): |
78 | | - start = start_dates[i] |
79 | | - end = end_dates[i] |
80 | | - |
81 | | - logging.info(f"Processing AOI {i+1}/{len(aois)}: {file}, {start} to {end}") |
82 | | - |
83 | | - # Build filters |
84 | | - geo_filter = filters.geometry_filter(aoi) |
85 | | - date_filter = filters.date_filter(start, end) |
86 | | - cloud_filter = filters.cloud_filter(cloud_max) |
87 | | - sun_filter = filters.sun_angle_filter(min_sun_angle) |
88 | | - |
89 | | - combined_filter = filters.combine_filters( |
90 | | - [geo_filter, date_filter, cloud_filter, sun_filter] |
91 | | - ) |
92 | 42 |
|
93 | | - # Determine if tiling is needed |
94 | | - area_km2 = geometry.compute_area_km2(aoi) |
95 | | - date_range_days = filters.compute_date_range_days(start, end) |
96 | | - |
97 | | - spatial_tiles = [aoi] |
98 | | - temporal_tiles = [(start, end)] |
99 | | - |
100 | | - if area_km2 > spatial_tile_threshold_km2: |
101 | | - spatial_tiles = geometry.spatial_tile(aoi) |
102 | | - logging.info( |
103 | | - "AOI exceeds %d km², applying spatial tiling: %d tiles", |
104 | | - spatial_tile_threshold_km2, |
105 | | - len(spatial_tiles), |
106 | | - ) |
107 | | - |
108 | | - if date_range_days > temporal_tile_threshold_days: |
109 | | - temporal_tiles = filters.temporal_tile(start, end) |
110 | | - logging.info( |
111 | | - "Date range exceeds %d days, applying temporal tiling: %d intervals", |
112 | | - temporal_tile_threshold_days, |
113 | | - len(temporal_tiles) |
114 | | - ) |
| 43 | +def load_aois(geojson_paths: List[str]): |
| 44 | + """ |
| 45 | + Load AOIs from GeoJSON files. |
| 46 | + |
| 47 | + Args: |
| 48 | + geojson_paths: List of AOI geojson paths. |
| 49 | + |
| 50 | + Returns: |
| 51 | + List of AOI geometries. |
| 52 | + """ |
| 53 | + aois = [load_aoi(path) for path in geojson_paths] |
| 54 | + logging.info("Loaded %d AOIs", len(aois)) |
| 55 | + return aois |
115 | 56 |
|
116 | | - # Fetch imagery and analyze for each tile |
117 | | - for s_tile in spatial_tiles: |
118 | | - for t_start, t_end in temporal_tiles: |
119 | | - logging.info( |
120 | | - f"Fetching imagery for tile and date range: {t_start} to {t_end}" |
121 | | - ) |
122 | | - try: |
123 | | - items = pagination.fetch_items( |
124 | | - geometry=s_tile, |
125 | | - start_date=t_start, |
126 | | - end_date=t_end, |
127 | | - cloud_max=cloud_max, |
128 | | - ) |
129 | | - analysis_results = analysis.compute_overlap(items, min_sun_angle) |
130 | | - analysis.save_results(analysis_results, output_dir) |
131 | | - logging.info(f"Saved results for tile ({t_start}-{t_end})") |
132 | | - except Exception as e: |
133 | | - logging.error(f"Failed processing tile/date {t_start}-{t_end}: {e}") |
134 | | - continue |
135 | 57 |
|
136 | | - logging.info("Planet Overlap workflow completed successfully.") |
| 58 | +def run_client( |
| 59 | + geojson_paths: List[str], |
| 60 | + date_ranges: List[Tuple[str, str]] |
| 61 | +): |
| 62 | + """ |
| 63 | + Full client workflow: load AOIs, prepare filters, and return filters + AOIs. |
| 64 | + |
| 65 | + Args: |
| 66 | + geojson_paths: List of AOI GeoJSON paths. |
| 67 | + date_ranges: List of (start_date, end_date) tuples. |
| 68 | + |
| 69 | + Returns: |
| 70 | + Tuple of (filters dict, list of AOI geometries) |
| 71 | + """ |
| 72 | + aois = load_aois(geojson_paths) |
| 73 | + filters = prepare_filters(geojson_paths, date_ranges) |
| 74 | + # Use filters downstream; previously 'combined_filter' was unused |
| 75 | + logging.info("Client run complete") |
| 76 | + return filters, aois |
0 commit comments