/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wps.gs.download; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import org.geotools.util.logging.Logging; import org.opengis.referencing.crs.CoordinateReferenceSystem; import com.vividsolutions.jts.geom.Geometry; /** * This class is used for managing ROI and its CRS. ROIManager provides utility method like reprojecting the ROI in the desired CRS. * * @author Simone Giannecchini, GeoSolutions * */ final class ROIManager { private static final Logger LOGGER = Logging.getLogger(ROIManager.class); /** Input Geometry */ final Geometry roi; /** ROI reprojected in the input ROI CRS */ Geometry roiInNativeCRS; /** ROI reprojected in the native ROI CRS (reduced to envelope if possible) */ Geometry safeRoiInNativeCRS; /** ROI native CRS */ CoordinateReferenceSystem nativeCRS; /** ROI reprojected in the target CRS */ Geometry roiInTargetCRS; /** ROI reprojected in the target CRS (reduced to envelope if possible) */ Geometry safeRoiInTargetCRS; /** Initial ROI CRS */ final CoordinateReferenceSystem roiCRS; /** ROI target CRS */ CoordinateReferenceSystem targetCRS; /** Boolean indicating if the ROI is a BBOX */ final boolean isROIBBOX; /** * Constructor. * * @param roi original ROI as a JTS geometry * @param roiCRS {@link CoordinateReferenceSystem} for the provided geometry. If this is null the CRS must be provided with the USerData of the * roi */ public ROIManager(Geometry roi, CoordinateReferenceSystem roiCRS) { this.roi = roi; DownloadUtilities.checkPolygonROI(roi); // Check ROI CRS if (roiCRS == null) { if (!(roi.getUserData() instanceof CoordinateReferenceSystem)) { throw new IllegalArgumentException("ROI without a CRS is not usable!"); } this.roiCRS = (CoordinateReferenceSystem) roi.getUserData(); } else { this.roiCRS = roiCRS; } roi.setUserData(this.roiCRS); // is this a bbox isROIBBOX = roi.isRectangle(); } /** * Reproject the initial roi to the provided CRS which is supposedly the native CRS of the data to clip. * * @param nativeCRS a valid instance of {@link CoordinateReferenceSystem} * @throws IOException in case something bad happens. */ public void useNativeCRS(final CoordinateReferenceSystem nativeCRS) throws IOException { if (nativeCRS == null) { throw new IllegalArgumentException("The provided nativeCRS is null"); } roiInNativeCRS = DownloadUtilities.transformGeometry(roi, nativeCRS); DownloadUtilities.checkPolygonROI(roiInNativeCRS); if (isROIBBOX) { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "ROI is a Bounding Box"); } // if the ROI is a BBOX we tend to preserve the fact that it is a BBOX safeRoiInNativeCRS = roiInNativeCRS.getEnvelope(); } else { if (LOGGER.isLoggable(Level.FINE)) { LOGGER.log(Level.FINE, "ROI is not a Bounding Box"); } safeRoiInNativeCRS = roiInNativeCRS; } safeRoiInNativeCRS.setUserData(nativeCRS); this.nativeCRS = nativeCRS; } /** * Reproject the initial roi to the provided CRS which is supposedly the target CRS as per the request. * * <p> * This method should be called once the native CRS has been set, that is the {@link #useNativeCRS(CoordinateReferenceSystem)} has been called. * * @param targetCRS a valid instance of {@link CoordinateReferenceSystem} * @throws IOException in case something bad happens. */ public void useTargetCRS(final CoordinateReferenceSystem targetCRS) throws IOException { if (targetCRS == null) { throw new IllegalArgumentException("The provided targetCRS is null"); } if (roiInNativeCRS == null) { throw new IllegalStateException("It looks like useNativeCRS has not been called yet"); } this.targetCRS = targetCRS; if (isROIBBOX) { // we need to use a larger bbox in native CRS roiInTargetCRS = DownloadUtilities.transformGeometry(safeRoiInNativeCRS, targetCRS); DownloadUtilities.checkPolygonROI(roiInTargetCRS); safeRoiInTargetCRS = roiInTargetCRS.getEnvelope(); safeRoiInTargetCRS.setUserData(targetCRS); // touch safeRoiInNativeCRS safeRoiInNativeCRS = DownloadUtilities.transformGeometry(safeRoiInTargetCRS, nativeCRS); DownloadUtilities.checkPolygonROI(safeRoiInNativeCRS); safeRoiInNativeCRS = safeRoiInNativeCRS.getEnvelope(); safeRoiInNativeCRS.setUserData(nativeCRS); } else { roiInTargetCRS = DownloadUtilities.transformGeometry(roiInNativeCRS, targetCRS); safeRoiInTargetCRS = roiInTargetCRS; } } /** * @return the isBBOX */ public boolean isROIBBOX() { return isROIBBOX; } /** * @return the roi */ public Geometry getRoi() { return roi; } /** * @return the roiInNativeCRS */ public Geometry getRoiInNativeCRS() { return roiInNativeCRS; } /** * @return the safeRoiInNativeCRS */ public Geometry getSafeRoiInNativeCRS() { return safeRoiInNativeCRS; } /** * @return the roiInTargetCRS */ public Geometry getRoiInTargetCRS() { return roiInTargetCRS; } /** * @return the safeRoiInTargetCRS */ public Geometry getSafeRoiInTargetCRS() { return safeRoiInTargetCRS; } /** * @return the roiCRS */ public CoordinateReferenceSystem getRoiCRS() { return roiCRS; } /** * @return the targetCRS */ public CoordinateReferenceSystem getTargetCRS() { return targetCRS; } }