diff --git a/CHANGELOG.md b/CHANGELOG.md index e4526737..4e4ac620 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,13 @@ and uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - --> +------ +## [v7.0.5](https://github.com/asfadmin/Discovery-asf_search/compare/v7.0.4...v7.0.5) +### Fixed +- Unwrapped WKT used in bounding box calculation when searching rectangular AOI +### Changed +- `dataset` and `platform` search keywords can now be used at the same time + ------ ## [v7.0.4](https://github.com/asfadmin/Discovery-asf_search/compare/v7.0.3...v7.0.4) ### Changed diff --git a/asf_search/WKT/validate_wkt.py b/asf_search/WKT/validate_wkt.py index 6a8f7681..cad67b24 100644 --- a/asf_search/WKT/validate_wkt.py +++ b/asf_search/WKT/validate_wkt.py @@ -11,7 +11,7 @@ from asf_search.exceptions import ASFWKTError -def validate_wkt(aoi: Union[str, BaseGeometry]) -> Tuple[BaseGeometry, List[RepairEntry]]: +def validate_wkt(aoi: Union[str, BaseGeometry]) -> Tuple[BaseGeometry, BaseGeometry, List[RepairEntry]]: """ Param aoi: the WKT string or Shapely Geometry to validate and prepare for the CMR query Validates the given area of interest, and returns a validated and simplified WKT string @@ -52,7 +52,7 @@ def _search_wkt_prep(shape: BaseGeometry): if isinstance(shape, Polygon): return orient(Polygon(shape.exterior), sign=1.0) -def _simplify_geometry(geometry: BaseGeometry) -> Tuple[BaseGeometry, List[RepairEntry]]: +def _simplify_geometry(geometry: BaseGeometry) -> Tuple[BaseGeometry, BaseGeometry, List[RepairEntry]]: """ param geometry: AOI Shapely Geometry to be prepped for CMR prepares geometry for CMR by: diff --git a/asf_search/search/search_generator.py b/asf_search/search/search_generator.py index 090182db..5632ade4 100644 --- a/asf_search/search/search_generator.py +++ b/asf_search/search/search_generator.py @@ -17,6 +17,7 @@ from asf_search.ASFSession import ASFSession from asf_search.ASFProduct import ASFProduct +from asf_search.CMR.translate import should_use_bbox from asf_search.exceptions import ASFSearch4xxError, ASFSearch5xxError, ASFSearchError, CMRIncompleteError from asf_search.constants import INTERNAL from asf_search.WKT.validate_wkt import validate_wkt @@ -80,9 +81,6 @@ def search_generator( (getattr(opts, 'granule_list', False) or getattr(opts, 'product_list', False)): raise ValueError("Cannot use maxResults along with product_list/granule_list.") - if opts.dataset is not None and opts.platform is not None: - raise ValueError("Cannot use dataset along with platform keyword in search.") - preprocess_opts(opts) url = '/'.join(s.strip('/') for s in [f'https://{opts.host}', f'{INTERNAL.CMR_GRANULE_PATH}']) @@ -169,20 +167,27 @@ def get_page(session: ASFSession, url: str, translated_opts: List) -> Response: def preprocess_opts(opts: ASFSearchOptions): + """Sets the appropriate WKT to pass along, sets default timezones + start/end order check, and transforms platform aliases to actual values""" # Repair WKT here so it only happens once, and you can save the result to the new Opts object: - wrap_wkt(opts=opts) - + select_wkt(opts=opts) + # Date/Time logic, convert "today" to the literal timestamp if needed: set_default_dates(opts=opts) # Platform Alias logic: set_platform_alias(opts=opts) - -def wrap_wkt(opts: ASFSearchOptions): +def select_wkt(opts: ASFSearchOptions): + """Validates the provided WKT, and chooses the appropriate version to use (wrapped or unwrapped) + - If we should use the bbox, we pass the unwrapped wkt (this will be used when building the bounding box) + - Otherwise, we pass the wrapped wkt + """ if opts.intersectsWith is not None: - wrapped, _, __ = validate_wkt(opts.intersectsWith) - opts.intersectsWith = wrapped.wkt + wrapped, unwrapped, _ = validate_wkt(opts.intersectsWith) + if should_use_bbox(wrapped): + opts.intersectsWith = unwrapped.wkt + else: + opts.intersectsWith = wrapped.wkt def set_default_dates(opts: ASFSearchOptions): diff --git a/tests/ASFSearchResults/test_ASFSearchResults.py b/tests/ASFSearchResults/test_ASFSearchResults.py index 357d6607..33f40ff5 100644 --- a/tests/ASFSearchResults/test_ASFSearchResults.py +++ b/tests/ASFSearchResults/test_ASFSearchResults.py @@ -182,4 +182,7 @@ def overlap_check(s1: BaseGeometry, s2: BaseGeometry): product_geom_wrapped, product_geom_unwrapped, _ = asf.validate_wkt(shape(product.geometry)) original_shape = unchanged_aoi - assert overlap_check(product_geom_wrapped, wrapped) or overlap_check(product_geom_wrapped, original_shape), f"OVERLAP FAIL: {product.properties['sceneName']}, {product.geometry} \nproduct: {product_geom_wrapped.wkt} \naoi: {wrapped.wkt}" + if asf.translate.should_use_bbox(original_shape): + assert overlap_check(product_geom_unwrapped, unwrapped) or overlap_check(product_geom_unwrapped, original_shape), f"OVERLAP FAIL: {product.properties['sceneName']}, {product.geometry} \nproduct: {product_geom_wrapped.wkt} \naoi: {wrapped.wkt}" + else: + assert overlap_check(product_geom_wrapped, wrapped) or overlap_check(product_geom_wrapped, original_shape), f"OVERLAP FAIL: {product.properties['sceneName']}, {product.geometry} \nproduct: {product_geom_wrapped.wkt} \naoi: {wrapped.wkt}"