Skip to content
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

Feat/customizable extent #19

Merged
merged 3 commits into from
May 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
172 changes: 106 additions & 66 deletions jaxa/earth/image/collection/bounds/set.py
Original file line number Diff line number Diff line change
@@ -1,52 +1,59 @@
#--------------------------------------------------------------------------------
# --------------------------------------------------------------------------------
# Load module
#--------------------------------------------------------------------------------
# --------------------------------------------------------------------------------
import sys
import math

#--------------------------------------------------------------------------------
# set_bbox :
#--------------------------------------------------------------------------------
def set_bbox_geojson(bbox,geoj,proj_params):

from qgis.core import QgsRectangle


# --------------------------------------------------------------------------------
# set_bbox :
# --------------------------------------------------------------------------------
def set_bbox_geojson(bbox, geoj, proj_params):
# Set min, max of lat,lon
LAT_RANGE = proj_params.lat_range_max
LON_RANGE = proj_params.lon_range_max
MIN_RANGE = proj_params.lon_min_width
UNIT = proj_params.unit_str
DECIMAL = proj_params.r_dec_bbox
UNIT = proj_params.unit_str
DECIMAL = proj_params.r_dec_bbox

# Initialize bbox if no input
if (bbox is None) & (geoj is None):
if "qgis.utils" in sys.modules:
bbox_out = set_bbox_qgis(proj_params.epsg)
bbox_out = fix_bbox(bbox_out,LAT_RANGE,LON_RANGE,MIN_RANGE,UNIT,DECIMAL)
bbox_out = fix_bbox(
bbox_out, LAT_RANGE, LON_RANGE, MIN_RANGE, UNIT, DECIMAL
)
geoj_out = bbox2geojson(bbox_out)
else:
bbox_out = [LON_RANGE[0],LAT_RANGE[0],LON_RANGE[1],LAT_RANGE[1]]
bbox_out = fix_bbox(bbox_out,LAT_RANGE,LON_RANGE,MIN_RANGE,UNIT,DECIMAL)
bbox_out = [LON_RANGE[0], LAT_RANGE[0], LON_RANGE[1], LAT_RANGE[1]]
bbox_out = fix_bbox(
bbox_out, LAT_RANGE, LON_RANGE, MIN_RANGE, UNIT, DECIMAL
)
geoj_out = bbox2geojson(bbox_out)

# Input geojson from bbox
elif geoj is None:
bbox_out = fix_bbox(bbox,LAT_RANGE,LON_RANGE,MIN_RANGE,UNIT,DECIMAL)
bbox_out = set_bbox_qgis(proj_params.epsg, bbox)
bbox_out = fix_bbox(bbox_out, LAT_RANGE, LON_RANGE, MIN_RANGE, UNIT, DECIMAL)
geoj_out = bbox2geojson(bbox_out)

# Input bbox from geojson
else:
bbox_out = geoj2bbox(geoj,DECIMAL)
bbox_out = fix_bbox(bbox_out,LAT_RANGE,LON_RANGE,MIN_RANGE,UNIT,DECIMAL)
bbox_out = geoj2bbox(geoj, DECIMAL)
bbox_out = fix_bbox(bbox_out, LAT_RANGE, LON_RANGE, MIN_RANGE, UNIT, DECIMAL)
geoj["bbox"] = bbox_out
geoj_out = geoj

# Output
return bbox_out, geoj_out

#--------------------------------------------------------------------------------
# geoj2bbox : Calculate bounding box of geojson
#--------------------------------------------------------------------------------
def geoj2bbox(geoj,DECIMAL):

# --------------------------------------------------------------------------------
# geoj2bbox : Calculate bounding box of geojson
# --------------------------------------------------------------------------------
def geoj2bbox(geoj, DECIMAL):
# Get lon, lat
lonlat = list(flatten_list(geoj["geometry"]["coordinates"]))

Expand All @@ -55,97 +62,130 @@ def geoj2bbox(geoj,DECIMAL):
latall = lonlat[1::2]

# Get bbox
bbox = [math.floor(min(lonall)*10**DECIMAL)/(10**DECIMAL),\
math.floor(min(latall)*10**DECIMAL)/(10**DECIMAL),\
math.ceil( max(lonall)*10**DECIMAL)/(10**DECIMAL),\
math.ceil( max(latall)*10**DECIMAL)/(10**DECIMAL)]
bbox = [
math.floor(min(lonall) * 10**DECIMAL) / (10**DECIMAL),
math.floor(min(latall) * 10**DECIMAL) / (10**DECIMAL),
math.ceil(max(lonall) * 10**DECIMAL) / (10**DECIMAL),
math.ceil(max(latall) * 10**DECIMAL) / (10**DECIMAL),
]

# Output
return bbox

#--------------------------------------------------------------------------------

# --------------------------------------------------------------------------------
# bbox2geojson
#--------------------------------------------------------------------------------
# --------------------------------------------------------------------------------
def bbox2geojson(bbox):

# Get coordinates from bbox
lonlat = [[bbox[0], bbox[1]],
[bbox[0], bbox[3]],
[bbox[2], bbox[3]],
[bbox[2], bbox[1]]]
lonlat = [
[bbox[0], bbox[1]],
[bbox[0], bbox[3]],
[bbox[2], bbox[3]],
[bbox[2], bbox[1]],
]

# Set geojson dict
geoj = {"bbox":bbox,
"geometry":{"coordinates":[lonlat],"type":"Polygon"},
"properties":{},
"type":"Feature"}
geoj = {
"bbox": bbox,
"geometry": {"coordinates": [lonlat], "type": "Polygon"},
"properties": {},
"type": "Feature",
}

# Output
return geoj

#--------------------------------------------------------------------------------

# --------------------------------------------------------------------------------
# flatten_list
#--------------------------------------------------------------------------------
# --------------------------------------------------------------------------------
def flatten_list(l):
for el in l:
if isinstance(el, list):
yield from flatten_list(el)
else:
yield el

Comment on lines +102 to 109
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

変数名 l は曖昧です。より説明的な名前に変更することをお勧めします。

- def flatten_list(l):
+ def flatten_list(nested_list):

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
# --------------------------------------------------------------------------------
def flatten_list(l):
for el in l:
if isinstance(el, list):
yield from flatten_list(el)
else:
yield el
# --------------------------------------------------------------------------------
def flatten_list(nested_list):
for el in nested_list:
if isinstance(el, list):
yield from flatten_list(el)
else:
yield el

#--------------------------------------------------------------------------------
# fix_bbox
#--------------------------------------------------------------------------------
def fix_bbox(bbox,LAT_RANGE,LON_RANGE,MIN_RANGE,UNIT,DECIMAL):

# --------------------------------------------------------------------------------
# fix_bbox
# --------------------------------------------------------------------------------
def fix_bbox(bbox, LAT_RANGE, LON_RANGE, MIN_RANGE, UNIT, DECIMAL):
# Check bbox length
if len(bbox) != 4:
raise Exception("Error! bbox_out needs 4 arguments!")

# Check bbox limit
if (bbox[0] < LON_RANGE[0]): bbox[0] = LON_RANGE[0]
if (bbox[0] > LON_RANGE[1]): bbox[0] = LON_RANGE[1]
if (bbox[1] < LAT_RANGE[0]): bbox[1] = LAT_RANGE[0]
if (bbox[1] > LAT_RANGE[1]): bbox[1] = LAT_RANGE[1]
if (bbox[2] < LON_RANGE[0]): bbox[2] = LON_RANGE[0]
if (bbox[2] > LON_RANGE[1]): bbox[2] = LON_RANGE[1]
if (bbox[3] < LAT_RANGE[0]): bbox[3] = LAT_RANGE[0]
if (bbox[3] > LAT_RANGE[1]): bbox[3] = LAT_RANGE[1]
if bbox[0] < LON_RANGE[0]:
bbox[0] = LON_RANGE[0]
if bbox[0] > LON_RANGE[1]:
bbox[0] = LON_RANGE[1]
if bbox[1] < LAT_RANGE[0]:
bbox[1] = LAT_RANGE[0]
if bbox[1] > LAT_RANGE[1]:
bbox[1] = LAT_RANGE[1]
if bbox[2] < LON_RANGE[0]:
bbox[2] = LON_RANGE[0]
if bbox[2] > LON_RANGE[1]:
bbox[2] = LON_RANGE[1]
if bbox[3] < LAT_RANGE[0]:
bbox[3] = LAT_RANGE[0]
if bbox[3] > LAT_RANGE[1]:
bbox[3] = LAT_RANGE[1]

# Check bbox range (small enough from MIN_RANGE)
eq1 = (not math.isclose(bbox[2]-bbox[0],MIN_RANGE)) and ((bbox[2]-bbox[0]) < MIN_RANGE)
eq2 = (not math.isclose(bbox[3]-bbox[1],MIN_RANGE)) and ((bbox[3]-bbox[1]) < MIN_RANGE)
if eq1 or eq2 :
raise Exception(f"Error! At least {MIN_RANGE} {UNIT} difference is need, Input bbox_out : {bbox}")
eq1 = (not math.isclose(bbox[2] - bbox[0], MIN_RANGE)) and (
(bbox[2] - bbox[0]) < MIN_RANGE
)
eq2 = (not math.isclose(bbox[3] - bbox[1], MIN_RANGE)) and (
(bbox[3] - bbox[1]) < MIN_RANGE
)
if eq1 or eq2:
raise Exception(
f"Error! At least {MIN_RANGE} {UNIT} difference is need, Input bbox_out : {bbox}"
)

# Round bbox_out
for i in range(len(bbox)):
bbox[i] = round(bbox[i],DECIMAL)
bbox[i] = round(bbox[i], DECIMAL)

# Output
return bbox

#--------------------------------------------------------------------------------
# set_bbox_qgis :
#--------------------------------------------------------------------------------
def set_bbox_qgis(epsg):

# --------------------------------------------------------------------------------
# set_bbox_qgis :
# --------------------------------------------------------------------------------
def set_bbox_qgis(epsg, bbox=None):
# Load module
from qgis.core import QgsCoordinateReferenceSystem,QgsCoordinateTransform,QgsProject
from qgis.core import (
QgsCoordinateReferenceSystem,
QgsCoordinateTransform,
QgsProject,
)
import qgis.utils

# Get displaying bounding box on QGIS crs
extent = qgis.utils.iface.mapCanvas().extent()
if bbox is None:
# Get displaying bounding box on QGIS crs
extent = qgis.utils.iface.mapCanvas().extent()
else:
# Transform bbox to QgsRectangle
extent = QgsRectangle(bbox[0], bbox[1], bbox[2], bbox[3])

# Transform crs to EPSG4326
source_crs = qgis.utils.iface.mapCanvas().mapSettings().destinationCrs()
dest_crs = QgsCoordinateReferenceSystem().fromEpsgId(epsg)
rtrans = QgsCoordinateTransform(source_crs,dest_crs,QgsProject.instance())
dest_crs = QgsCoordinateReferenceSystem().fromEpsgId(epsg)
rtrans = QgsCoordinateTransform(source_crs, dest_crs, QgsProject.instance())
extent_out = rtrans.transformBoundingBox(extent)

# Extent to bbox
bbox = [extent_out.xMinimum(),extent_out.yMinimum(),
extent_out.xMaximum(),extent_out.yMaximum()]

out_bbox = [
extent_out.xMinimum(),
extent_out.yMinimum(),
extent_out.xMaximum(),
extent_out.yMaximum(),
]

# Output
return bbox
return out_bbox
31 changes: 25 additions & 6 deletions jaxaEarthApiDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from PyQt5.QtWidgets import *
from qgis.core import *
from qgis.gui import *
from qgis.utils import iface

# Load module
from .jaxa.earth import je
Expand Down Expand Up @@ -96,15 +97,15 @@ def classify_datasets(self):

for dataset_name, dataset_info in CATALOG.items():
bbox = dataset_info["bbox"][0]
logitude_W = int(bbox[0])
logitude_E = int(bbox[2])
logitude = [logitude_W, logitude_E]
longitude_W = int(bbox[0])
longitude_E = int(bbox[2])
longitude = [longitude_W, longitude_E]

_dataset_info = {**dataset_info, "key": dataset_name}

if logitude == [-180, 180]:
if longitude == [-180, 180]:
classes["globe"].append(_dataset_info)
elif -180 < logitude_W < 180:
elif -180 < longitude_W < 180:
classes["local"].append(_dataset_info)
else:
classes["unknown"].append(_dataset_info)
Expand Down Expand Up @@ -139,6 +140,17 @@ def init_gui(self):
self.datasetCombobox.currentIndexChanged.connect(self.on_dataset_changed)
self.bandCombobox.currentIndexChanged.connect(self.on_dataset_changed)

# QgsExtentGroupBox
self.ui.mExtentGroupBox.setMapCanvas(iface.mapCanvas())
self.ui.mExtentGroupBox.setOutputCrs(QgsProject.instance().crs())
self.ui.mExtentGroupBox.setOutputExtentFromCurrent()
QgsProject.instance().crsChanged.connect(
lambda: [
self.ui.mExtentGroupBox.setOutputCrs(QgsProject.instance().crs()),
self.ui.mExtentGroupBox.setOutputExtentFromCurrent(),
]
)

def on_dataset_changed(self):
self.loadButton.setEnabled(self.is_executable())
self.detailsButton.setEnabled(self.is_executable())
Expand Down Expand Up @@ -271,6 +283,13 @@ def load_dataset(self):
start_datetime = self.startDateEdit.date().toString("yyyy-MM-dd") + "T00:00:00"
end_datetime = self.endDateEdit.date().toString("yyyy-MM-dd") + "T23:59:59"

extent = [
self.ui.mExtentGroupBox.outputExtent().xMinimum(),
self.ui.mExtentGroupBox.outputExtent().yMinimum(),
self.ui.mExtentGroupBox.outputExtent().xMaximum(),
self.ui.mExtentGroupBox.outputExtent().yMaximum(),
]

# Get an image
try:
data = (
Expand All @@ -280,7 +299,7 @@ def load_dataset(self):
)
.filter_date([start_datetime, end_datetime])
.filter_resolution()
.filter_bounds(bbox=None) # implicitly use MapCanvas Extent
.filter_bounds(bbox=extent)
.select(band)
.get_images()
)
Expand Down
11 changes: 11 additions & 0 deletions jaxaEarthApiDialog.ui
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,19 @@
</item>
</layout>
</item>
<item row="3" column="1">
<widget class="QgsExtentGroupBox" name="mExtentGroupBox"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsExtentGroupBox</class>
<extends>QgsCollapsibleGroupBox</extends>
<header>qgsextentgroupbox.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>