/* * Copyright (c) 2016, Metron, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Metron, Inc. nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL METRON, INC. BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.metsci.glimpse.dnc; import static com.metsci.glimpse.dnc.DncTangentPlanes.azimuthToTangentPlane_MATHRAD; import static com.metsci.glimpse.dnc.DncTangentPlanes.posToTangentPlane; import static java.lang.Math.sqrt; import com.metsci.glimpse.dnc.DncTangentPlanes.DncTangentPlane; import com.metsci.glimpse.util.vector.Vector2d; public class DncProjections { public interface DncProjection { String configString( ); double suggestedPpvMultiplier( ); boolean canProjectLibrary( int databaseNum, String libraryName, double minLat_DEG, double maxLat_DEG, double minLon_DEG, double maxLon_DEG ); void projectPos( double lat_DEG, double lon_DEG, float[] result, int resultOffset ); double projectAzimuth_MATHRAD( double x, double y, double azimuth_MATHRAD ); } public static boolean canProjectBrowse( DncProjection proj ) { return proj.canProjectLibrary( 1, "BROWSE", -90, 90, -180, 180 ); } public static final DncProjection dncPlateCarree = new DncProjection( ) { public String configString( ) { return "PlateCarree"; } public double suggestedPpvMultiplier( ) { return 1; } public boolean canProjectLibrary( int databaseNum, String libraryName, double minLat_DEG, double maxLat_DEG, double minLon_DEG, double maxLon_DEG ) { return true; } public void projectPos( double lat_DEG, double lon_DEG, float[] result, int resultOffset ) { result[ resultOffset + 0 ] = ( float ) lon_DEG; result[ resultOffset + 1 ] = ( float ) lat_DEG; } public double projectAzimuth_MATHRAD( double x, double y, double azimuth_MATHRAD ) { // XXX return azimuth_MATHRAD; } }; public static final DncProjection dncTangentPlane( double tangentLat_DEG, double tangentLon_DEG ) { return dncTangentPlane( tangentLat_DEG, tangentLon_DEG, 0.0, 0.0 ); } public static final DncProjection dncTangentPlane( double tangentLat_DEG, double tangentLon_DEG, Vector2d tangentPointOnPlane ) { return dncTangentPlane( tangentLat_DEG, tangentLon_DEG, tangentPointOnPlane.getX( ), tangentPointOnPlane.getY( ) ); } public static final DncProjection dncTangentPlane( final double tangentLat_DEG, final double tangentLon_DEG, final double tangentPointOnPlaneX, final double tangentPointOnPlaneY ) { return new DncProjection( ) { DncTangentPlane plane = new DncTangentPlane( tangentLat_DEG, tangentLon_DEG ); public String configString( ) { return "TangentPlane[ " + plane.tangentLat_DEG + "," + plane.tangentLon_DEG + " ]"; } public double suggestedPpvMultiplier( ) { // Larger -> more crowded display // Smaller -> emptier display double empiricalTweakFactor = 2; float[] p0 = new float[ 2 ]; projectPos( plane.tangentLat_DEG, plane.tangentLon_DEG - 0.5, p0, 0 ); float[] p1 = new float[ 2 ]; projectPos( plane.tangentLat_DEG, plane.tangentLon_DEG + 0.5, p1, 0 ); float dx = p0[ 0 ] - p1[ 0 ]; float dy = p0[ 1 ] - p1[ 1 ]; return sqrt( empiricalTweakFactor * ( dx*dx + dy*dy ) ); } public boolean canProjectLibrary( int databaseNum, String libraryName, double minLat_DEG, double maxLat_DEG, double minLon_DEG, double maxLon_DEG ) { double antipodeLat_DEG = -tangentLat_DEG; double antipodeLon_DEG = normalizeLon( minLon_DEG, tangentLon_DEG + 180 ); boolean libraryContainsAntipode = ( minLat_DEG <= antipodeLat_DEG && antipodeLat_DEG <= maxLat_DEG && minLon_DEG <= antipodeLon_DEG && antipodeLon_DEG <= maxLon_DEG ); return ( !libraryContainsAntipode ); } protected double normalizeLon( double minLon_DEG, double lon_DEG ) { double offset_DEG = ( lon_DEG - minLon_DEG ) % 360; if ( offset_DEG < 0 ) offset_DEG += 360; return ( minLon_DEG + offset_DEG ); } public void projectPos( double lat_DEG, double lon_DEG, float[] result, int resultOffset ) { posToTangentPlane( plane, lat_DEG, lon_DEG, result, resultOffset ); } public double projectAzimuth_MATHRAD( double x, double y, double azimuth_MATHRAD ) { return azimuthToTangentPlane_MATHRAD( plane, x, y, azimuth_MATHRAD ); } }; } }