11module Modland
22
3+ # MODLAND.jl: Utilities for working with MODIS land grid and projections
4+ # Provides functions to convert between latitude/longitude and MODIS sinusoidal projection,
5+ # and to determine MODIS tile indices for given coordinates or polygons.
6+
7+
8+ # Import required packages for geospatial operations and data handling
39import ArchGDAL as AG
410import ArchGDAL
511import GeoDataFrames as GDF
612import GeoFormatTypes as GFT
713using DataFrames
814using Rasters
9- using DimensionalData. Dimensions. LookupArrays
1015import JSON
1116
12- # boundaries of sinusodial projection
13- UPPER_LEFT_X_METERS = - 20015109.355798
14- UPPER_LEFT_Y_METERS = 10007554.677899
15- LOWER_RIGHT_X_METERS = 20015109.355798
16- LOWER_RIGHT_Y_METERS = - 10007554.677899
1717
18- # size across (width or height) of any equal-area sinusoidal target
18+ # Constants defining the boundaries of the MODIS sinusoidal projection (in meters)
19+ UPPER_LEFT_X_METERS = - 20015109.355798 # Westernmost x coordinate
20+ UPPER_LEFT_Y_METERS = 10007554.677899 # Northernmost y coordinate
21+ LOWER_RIGHT_X_METERS = 20015109.355798 # Easternmost x coordinate
22+ LOWER_RIGHT_Y_METERS = - 10007554.677899 # Southernmost y coordinate
23+
24+ # Size (width or height) of a MODIS tile in the sinusoidal projection (in meters)
1925TILE_SIZE_METERS = 1111950.5197665554
2026
21- # boundaries of MODIS land grid
27+ # Number of rows and columns in the MODIS land grid
2228TOTAL_ROWS = 18
2329TOTAL_COLUMNS = 36
2430
31+ # Coordinate reference systems (CRS) for WGS84 and MODIS sinusoidal projection
2532WGS84 = ProjString (" +proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" )
2633SINUSOIDAL = ProjString (" +proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs" )
2734
28- export UPPER_LEFT_X_METERS, UPPER_LEFT_Y_METERS, LOWER_RIGHT_X_METERS, LOWER_RIGHT_Y_METERS, TILE_SIZE_METERS, TOTAL_ROWS, TOTAL_COLUMNS, WGS84, SINUSOIDAL
29-
3035
3136"""
32- latlon_to_sinusoidal(lat::Float64, lon::Float64)::Tuple{ Float64,Float64}
37+ latlon_to_sinusoidal(lat::Float64, lon::Float64) -> (x:: Float64, y:: Float64)
3338
34- Convert latitude and longitude coordinates to sinusoidal projection coordinates.
39+ Convert latitude and longitude (in degrees, WGS84) to MODIS sinusoidal projection coordinates (in meters) .
3540
36- # Arguments
37- - ` lat::Float64` : Latitude in degrees.
38- - ` lon::Float64` : Longitude in degrees.
41+ Arguments:
42+ lat::Float64: Latitude in degrees (-90 to 90)
43+ lon::Float64: Longitude in degrees (-180 to 180)
3944
40- # Returns
41- - `Tuple{Float64, Float64}`: Sinusoidal projection coordinates (x, y).
45+ Returns:
46+ Tuple (x, y): Sinusoidal projection coordinates in meters
47+
48+ Throws:
49+ Error if latitude or longitude is out of bounds.
4250"""
4351function latlon_to_sinusoidal (lat:: Float64 , lon:: Float64 ):: Tuple{Float64,Float64}
44- # Check if latitude is within valid bounds
52+ # Validate latitude
4553 if lat < - 90 || lat > 90
4654 error (" latitude ($(lat) ) out of bounds" )
4755 end
48-
49- # Check if longitude is within valid bounds
56+ # Validate longitude
5057 if lon < - 180 || lon > 180
5158 error (" longitude ($(lon) )) out of bounds" )
5259 end
5360
54- # Create a point in latitude and longitude coordinates
61+ # Create a point in WGS84 and reproject to sinusoidal
5562 point_latlon = AG. createpoint (lon, lat)
56- # Reproject the point from WGS84 to sinusoidal projection
5763 point_sinusoidal = AG. reproject (point_latlon, WGS84, SINUSOIDAL)
58- # Extract the x coordinate from the reprojected point
5964 x = AG. getx (point_sinusoidal, 0 )
60- # Extract the y coordinate from the reprojected point
6165 y = AG. gety (point_sinusoidal, 0 )
6266
63- # Return the sinusoidal coordinates as a tuple
6467 return x, y
6568end
6669
6770export latlon_to_sinusoidal
6871
72+
6973"""
70- sinusoidal_to_modland(x::Float64, y::Float64)::String
74+ sinusoidal_to_MODLAND(x::Float64, y::Float64) -> String
75+
76+ Given sinusoidal projection coordinates (x, y), return the MODIS land tile index (e.g., "h12v04")
77+ that contains the point.
7178
72- Convert sinusoidal projection coordinates to MODIS land tile indices.
79+ Arguments:
80+ x::Float64: Sinusoidal x coordinate (meters)
81+ y::Float64: Sinusoidal y coordinate (meters)
7382
74- # Arguments
75- - `x::Float64`: Sinusoidal x coordinate.
76- - `y::Float64`: Sinusoidal y coordinate.
83+ Returns:
84+ String: MODIS tile index in the format "hXXvYY"
7785
78- # Returns
79- - `String`: MODIS land tile index in the format "hXXvYY" .
86+ Throws:
87+ Error if x or y is out of bounds for the MODIS grid .
8088"""
81- function sinusoidal_to_modland (x:: Float64 , y:: Float64 ):: String
82- # Check if the x coordinate is within the valid bounds of the sinusoidal projection
89+ function sinusoidal_to_MODLAND (x:: Float64 , y:: Float64 ):: String
90+ # Check if x is within the valid range
8391 if x < UPPER_LEFT_X_METERS || x > LOWER_RIGHT_X_METERS
8492 error (" sinusoidal x coordinate ($(x) ) out of bounds" )
8593 end
86-
87- # Check if the y coordinate is within the valid bounds of the sinusoidal projection
94+ # Check if y is within the valid range
8895 if y < LOWER_RIGHT_Y_METERS || y > UPPER_LEFT_Y_METERS
8996 error (" sinusoidal y ($(y) )) coordinate out of bounds" )
9097 end
9198
92- # Calculate the horizontal tile index
99+ # Calculate horizontal (column) and vertical (row) indices
93100 horizontal_index = Int (floor ((x - UPPER_LEFT_X_METERS) / TILE_SIZE_METERS))
94- # Calculate the vertical tile index
95101 vertical_index = Int (floor ((- 1 * (y + LOWER_RIGHT_Y_METERS)) / TILE_SIZE_METERS))
96102
97- # Adjust the horizontal index if it is at the boundary
103+ # Clamp indices to valid range if on the edge
98104 if horizontal_index == TOTAL_COLUMNS
99105 horizontal_index -= 1
100106 end
101-
102- # Adjust the vertical index if it is at the boundary
103107 if vertical_index == TOTAL_ROWS
104108 vertical_index -= 1
105109 end
106110
107- # Format the tile index as a string in the format "hXXvYY"
111+ # Format as MODIS tile string (e.g., h12v04)
108112 tile = " h$(lpad (horizontal_index, 2 , ' 0' )) v$(lpad (vertical_index, 2 , ' 0' )) "
113+ return tile
114+ end
115+
116+ export sinusoidal_to_MODLAND
117+
118+
119+ """
120+ latlon_to_MODLAND(lat, lon) -> String
109121
110- # Return the formatted tile index
122+ Convert latitude and longitude (in degrees, WGS84) directly to the MODIS land tile index (e.g., "h12v04").
123+
124+ Arguments:
125+ lat: Latitude in degrees
126+ lon: Longitude in degrees
127+
128+ Returns:
129+ String: MODIS tile index in the format "hXXvYY"
130+ """
131+ function latlon_to_MODLAND (lat, lon)
132+ # Convert lat/lon to sinusoidal coordinates
133+ x, y = latlon_to_sinusoidal (lat, lon)
134+ # Get MODIS tile index for the coordinates
135+ tile = sinusoidal_to_MODLAND (x, y)
111136 return tile
112137end
113138
114- export sinusoidal_to_modland
139+ export latlon_to_MODLAND
140+
141+
142+ """
143+ MODLAND_tiles_in_polygon(poly::ArchGDAL.IGeometry{ArchGDAL.wkbPolygon25D}) -> Set{String}
144+ MODLAND_tiles_in_polygon(poly::AG.IGeometry{AG.wkbPolygon}) -> Set{String}
145+
146+ Given a polygon geometry, return the set of MODIS land tile indices that contain the polygon's vertices.
147+ Note: Only the tiles containing the polygon's vertices are returned, not all tiles intersecting the polygon.
148+
149+ Arguments:
150+ poly: Polygon geometry (ArchGDAL.IGeometry)
115151
116- end
152+ Returns:
153+ Set{String}: Set of MODIS tile indices (e.g., Set(["h12v04", ...]))
154+ """
155+ function MODLAND_tiles_in_polygon (poly:: ArchGDAL.IGeometry{ArchGDAL.wkbPolygon25D} ):: Set{String}
156+ # Convert polygon to JSON, extract coordinates, and map to MODIS tiles
157+ Set ([latlon_to_MODLAND (lat, lon) for (lon, lat) in JSON. parse (AG. toJSON (poly))[" coordinates" ][1 ]])
158+ end
159+
160+ function MODLAND_tiles_in_polygon (poly:: AG.IGeometry{AG.wkbPolygon} ):: Set{String}
161+ # Convert polygon to JSON, extract coordinates, and map to MODIS tiles
162+ Set ([latlon_to_MODLAND (lat, lon) for (lon, lat) in JSON. parse (AG. toJSON (poly))[" coordinates" ][1 ]])
163+ end
164+
165+ export MODLAND_tiles_in_polygon
166+
167+ end
0 commit comments