jiayuasu commented on code in PR #2677:
URL: https://github.com/apache/sedona/pull/2677#discussion_r2868772533


##########
common/src/main/java/org/apache/sedona/common/raster/RasterEditors.java:
##########
@@ -102,7 +114,278 @@ public static GridCoverage2D setSrid(GridCoverage2D 
raster, int srid) {
     } else {
       crs = FunctionsGeoTools.sridToCRS(srid);
     }
+    return replaceCrs(raster, crs);
+  }
+
+  /**
+   * Sets the CRS of a raster using a CRS string. Accepts EPSG codes (e.g. 
"EPSG:4326"), WKT1, WKT2,
+   * PROJ strings, and PROJJSON.
+   *
+   * @param raster The input raster.
+   * @param crsString The CRS definition string.
+   * @return The raster with the new CRS.
+   */
+  public static GridCoverage2D setCrs(GridCoverage2D raster, String crsString) 
{
+    CoordinateReferenceSystem crs = parseCrsString(crsString);
+    return replaceCrs(raster, crs);
+  }
+
+  /**
+   * Parse a CRS string in any supported format into a GeoTools 
CoordinateReferenceSystem.
+   *
+   * <p>Parsing priority:
+   *
+   * <ol>
+   *   <li>GeoTools CRS.decode — handles authority codes like EPSG:4326
+   *   <li>GeoTools CRS.parseWKT — handles WKT1 strings
+   *   <li>proj4sedona — handles WKT2, PROJ strings, PROJJSON. If an EPSG 
authority can be resolved,
+   *       uses CRS.decode for a lossless result. Otherwise falls back to WKT1 
conversion.
+   * </ol>
+   *
+   * @param crsString The CRS definition string.
+   * @return The parsed CoordinateReferenceSystem.
+   * @throws IllegalArgumentException if the CRS string cannot be parsed.
+   */
+  static CoordinateReferenceSystem parseCrsString(String crsString) {
+    // Step 1: Try GeoTools CRS.decode (handles EPSG:xxxx, AUTO:xxxx, etc.)
+    try {
+      return CRS.decode(crsString, true);
+    } catch (FactoryException e) {
+      // Not an authority code, continue
+    }
+
+    // Step 2: Try GeoTools CRS.parseWKT (handles WKT1)
+    try {
+      return CRS.parseWKT(crsString);
+    } catch (FactoryException e) {
+      // Not WKT1, continue
+    }
+
+    // Step 3: Use proj4sedona (handles WKT2, PROJ, PROJJSON)
+    try {
+      Proj proj = new Proj(crsString);
+
+      // Try to resolve to an EPSG authority code for a lossless result
+      String authority = proj.toEpsgCode();
+      if (authority != null && !authority.isEmpty()) {
+        try {
+          return CRS.decode(authority, true);
+        } catch (FactoryException ex) {
+          // Authority code not recognized by GeoTools, fall through to WKT1
+        }
+      }
+
+      // Fallback: convert to WKT1 via proj4sedona and parse with GeoTools.
+      // proj4sedona may include parameters GeoTools doesn't expect (e.g. 
standard_parallel_1
+      // for projections that don't use it). We handle this by trying several 
parse strategies:
+      // 1. Raw WKT1 (proj4sedona's projection names may already be recognized 
by GeoTools)
+      // 2. Normalized WKT1 (resolve projection names to canonical OGC names)
+      // 3. Strip unexpected parameters iteratively
+      String wkt1 = proj.toWkt1();
+      if (wkt1 != null && !wkt1.isEmpty()) {
+        // Strategy 1: Try raw WKT1 directly
+        try {
+          return CRS.parseWKT(wkt1);
+        } catch (FactoryException ex) {
+          // Raw WKT1 failed, continue with normalization
+        }
+
+        // Strategy 2: Try with normalized projection name
+        String normalizedWkt = normalizeWkt1ProjectionName(wkt1);
+        // Strategy 3: If parsing fails due to unexpected parameters, strip 
them iteratively.
+        // proj4sedona sometimes includes parameters like standard_parallel_1 
for projections
+        // that don't use it. We parse the error message to identify and 
remove the offending
+        // parameter, then retry.
+        String currentWkt = normalizedWkt;
+        for (int attempt = 0; attempt < 5; attempt++) {
+          try {
+            return CRS.parseWKT(currentWkt);
+          } catch (FactoryException ex) {
+            String msg = ex.getMessage();
+            if (msg != null) {
+              Matcher paramMatcher = UNEXPECTED_PARAM_PATTERN.matcher(msg);
+              if (paramMatcher.find()) {
+                currentWkt = stripWktParameter(currentWkt, 
paramMatcher.group(1));
+                continue;
+              }
+            }
+            break; // Different kind of error, give up
+          }
+        }
+      }
+    } catch (Exception e) {
+      // proj4sedona could not parse it either
+    }

Review Comment:
   Fixed.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to