package mil.nga.giat.geowave.analytic; import java.util.LinkedList; import java.util.List; import javax.measure.converter.ConversionException; import javax.measure.quantity.Length; import javax.measure.unit.SI; import javax.measure.unit.Unit; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.referencing.GeodeticCalculator; import org.opengis.geometry.DirectPosition; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.opengis.referencing.operation.TransformException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.PrecisionModel; public class GeometryCalculations { private static final Logger LOGGER = LoggerFactory.getLogger(GeometryCalculations.class); final GeometryFactory factory; final CoordinateReferenceSystem crs; final double xMin, yMin, xMax, yMax; public GeometryCalculations( CoordinateReferenceSystem crs ) { factory = new GeometryFactory( new PrecisionModel(), 4326); this.crs = crs; xMin = crs.getCoordinateSystem().getAxis( 0).getMinimumValue(); xMax = crs.getCoordinateSystem().getAxis( 0).getMaximumValue(); yMin = crs.getCoordinateSystem().getAxis( 1).getMinimumValue(); yMax = crs.getCoordinateSystem().getAxis( 1).getMaximumValue(); } /** * Build geometries with the provided coordinate at the center. The width of * the geometry is twice the distance provided. More than one geometry is * return when passing the date line. * * @param distances * [x,y] = [longitude, latitude] * @param unit * @param coordinate * @return */ public List<Geometry> buildSurroundingGeometries( final double[] distances, final Unit<Length> unit, Coordinate coordinate ) { List<Geometry> geos = new LinkedList<Geometry>(); GeodeticCalculator geoCalc = new GeodeticCalculator(); geoCalc.setStartingGeographicPoint( coordinate.x, coordinate.y); try { geoCalc.setDirection( 0, unit.getConverterTo( SI.METER).convert( distances[1])); DirectPosition north = geoCalc.getDestinationPosition(); geoCalc.setDirection( 90, unit.getConverterTo( SI.METER).convert( distances[0])); DirectPosition east = geoCalc.getDestinationPosition(); geoCalc.setStartingGeographicPoint( coordinate.x, coordinate.y); geoCalc.setDirection( -90, unit.getConverterTo( SI.METER).convert( distances[0])); DirectPosition west = geoCalc.getDestinationPosition(); geoCalc.setDirection( 180, unit.getConverterTo( SI.METER).convert( distances[1])); DirectPosition south = geoCalc.getDestinationPosition(); double x1 = west.getOrdinate(0); double x2 = east.getOrdinate(0); double y1 = north.getOrdinate(1); double y2 = south.getOrdinate(1); handleBoundaries( geos, coordinate, x1, x2, y1, y2); return geos; } catch (IllegalArgumentException | IndexOutOfBoundsException | TransformException | ConversionException ex) { LOGGER.error( "Unable to build geometry", ex); } return null; } private void handleBoundaries( List<Geometry> geos, Coordinate coordinate, double x1, double x2, double y1, double y2 ) { if (Math.signum(x1) > Math.signum(coordinate.x)) { ReferencedEnvelope bounds = new ReferencedEnvelope( x1, xMax, Math.max( y1, yMin), Math.min( y2, yMax), crs); geos.add(factory.toGeometry(bounds)); bounds = new ReferencedEnvelope( xMin, x2, Math.max( y1, yMin), Math.min( y2, yMax), crs); geos.add(factory.toGeometry(bounds)); } else if (Math.signum(x2) < Math.signum(coordinate.x)) { ReferencedEnvelope bounds = new ReferencedEnvelope( xMin, x2, Math.max( y1, yMin), Math.min( y2, yMax), crs); geos.add(factory.toGeometry(bounds)); bounds = new ReferencedEnvelope( x1, xMax, Math.max( y1, yMin), Math.min( y2, yMax), crs); geos.add(factory.toGeometry(bounds)); } else { final ReferencedEnvelope bounds = new ReferencedEnvelope( x1, x2, Math.max( y1, yMin), Math.min( y2, yMax), crs); geos.add(factory.toGeometry(bounds)); } } }