001 /*
002 * This file is part of McIDAS-V
003 *
004 * Copyright 2007-2013
005 * Space Science and Engineering Center (SSEC)
006 * University of Wisconsin - Madison
007 * 1225 W. Dayton Street, Madison, WI 53706, USA
008 * https://www.ssec.wisc.edu/mcidas
009 *
010 * All Rights Reserved
011 *
012 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
013 * some McIDAS-V source code is based on IDV and VisAD source code.
014 *
015 * McIDAS-V is free software; you can redistribute it and/or modify
016 * it under the terms of the GNU Lesser Public License as published by
017 * the Free Software Foundation; either version 3 of the License, or
018 * (at your option) any later version.
019 *
020 * McIDAS-V is distributed in the hope that it will be useful,
021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023 * GNU Lesser Public License for more details.
024 *
025 * You should have received a copy of the GNU Lesser Public License
026 * along with this program. If not, see http://www.gnu.org/licenses.
027 */
028
029 package edu.wisc.ssec.mcidasv.control;
030
031 import visad.georef.MapProjection;
032 import visad.data.hdfeos.LambertAzimuthalEqualArea;
033 import visad.RealTupleType;
034 import visad.CoordinateSystem;
035 import visad.Data;
036 import visad.SI;
037 import visad.Unit;
038 import java.awt.geom.Rectangle2D;
039 import visad.VisADException;
040 import java.rmi.RemoteException;
041
042
043 public class LambertAEA extends MapProjection {
044
045 CoordinateSystem cs;
046 Rectangle2D rect;
047 float earthRadius = 6367470; //- meters
048
049 public LambertAEA(float[][] corners, float lonCenter, float latCenter) throws VisADException {
050 super(RealTupleType.SpatialEarth2DTuple, new Unit[] {SI.meter, SI.meter});
051
052 cs = new LambertAzimuthalEqualArea(RealTupleType.SpatialEarth2DTuple, earthRadius,
053 lonCenter*Data.DEGREES_TO_RADIANS, latCenter*Data.DEGREES_TO_RADIANS,
054 0,0);
055
056 float[][] xy = cs.fromReference(corners);
057
058 float min_x = Float.MAX_VALUE;
059 float min_y = Float.MAX_VALUE;
060 float max_x = -Float.MAX_VALUE;
061 float max_y = -Float.MAX_VALUE;
062
063 for (int k=0; k<xy[0].length;k++) {
064 if (xy[0][k] < min_x) min_x = xy[0][k];
065 if (xy[1][k] < min_y) min_y = xy[1][k];
066 if (xy[0][k] > max_x) max_x = xy[0][k];
067 if (xy[1][k] > max_y) max_y = xy[1][k];
068 }
069
070 float del_x = max_x - min_x;
071 float del_y = max_y - min_y;
072
073 boolean forceSquareMapArea = true;
074 if (forceSquareMapArea) {
075 if (del_x < del_y) {
076 del_x = del_y;
077 }
078 else if (del_y < del_x) {
079 del_y = del_x;
080 }
081 }
082
083 rect = new Rectangle2D.Float(-del_x/2, -del_y/2, del_x, del_y);
084 }
085
086 public LambertAEA(float[][] corners) throws VisADException {
087 super(RealTupleType.SpatialEarth2DTuple, new Unit[] {SI.meter, SI.meter});
088
089 boolean spanGM = false;
090 float lonA = corners[0][0];
091 float lonB = corners[0][1];
092 float lonC = corners[0][2];
093 float lonD = corners[0][3];
094 float latA = corners[1][0];
095 float latB = corners[1][1];
096 float latC = corners[1][2];
097 float latD = corners[1][3];
098
099 float diffAD = lonA - lonD;
100 //float diffBC = lonB - lonC;
101
102 if (Math.abs(diffAD) > 180) spanGM = true;
103 //if (Math.abs(diffBC) > 180) spanGM = true;
104
105 float lonCenter;
106
107 if (spanGM) {
108 float[] vals = MultiSpectralControl.minmax(new float[] {lonA, lonD});
109 float wLon = vals[1];
110 float eLon = vals[0];
111 float del = 360f - wLon + eLon;
112 lonCenter = wLon + del/2;
113 if (lonCenter > 360) lonCenter -= 360f;
114 }
115 else {
116 float[] vals = MultiSpectralControl.minmax(new float[] {lonA, lonD});
117 float minLon = vals[0];
118 float maxLon = vals[1];
119 lonCenter = minLon + (maxLon - minLon)/2;
120 }
121
122 float[] vals = MultiSpectralControl.minmax(corners[1]);
123 float minLat = vals[0];
124 float maxLat = vals[1];
125 float latCenter = minLat + (maxLat - minLat)/2;
126
127 cs = new LambertAzimuthalEqualArea(RealTupleType.SpatialEarth2DTuple, earthRadius,
128 lonCenter*Data.DEGREES_TO_RADIANS, latCenter*Data.DEGREES_TO_RADIANS,
129 0,0);
130
131 float[][] xy = cs.fromReference(corners);
132
133 float min_x = Float.MAX_VALUE;
134 float min_y = Float.MAX_VALUE;
135 float max_x = Float.MIN_VALUE;
136 float max_y = Float.MIN_VALUE;
137
138 for (int k=0; k<xy[0].length;k++) {
139 if (xy[0][k] < min_x) min_x = xy[0][k];
140 if (xy[1][k] < min_y) min_y = xy[1][k];
141 if (xy[0][k] > max_x) max_x = xy[0][k];
142 if (xy[1][k] > max_y) max_y = xy[1][k];
143 }
144
145 float del_x = max_x - min_x;
146 float del_y = max_y - min_y;
147
148 boolean forceSquareMapArea = true;
149 if (forceSquareMapArea) {
150 if (del_x < del_y) {
151 del_x = del_y;
152 }
153 else if (del_y < del_x) {
154 del_y = del_x;
155 }
156 }
157
158 min_x = -del_x/2;
159 min_y = -del_y/2;
160
161 rect = new Rectangle2D.Float(min_x, min_y, del_x, del_y);
162 }
163
164 public LambertAEA(Rectangle2D ll_rect) throws VisADException {
165 this(ll_rect, true);
166 }
167
168 public LambertAEA(Rectangle2D ll_rect, boolean forceSquareMapArea) throws VisADException {
169 super(RealTupleType.SpatialEarth2DTuple, new Unit[] {SI.meter, SI.meter});
170
171 float minLon = (float) ll_rect.getX();
172 float minLat = (float) ll_rect.getY();
173 float del_lon = (float) ll_rect.getWidth();
174 float del_lat = (float) ll_rect.getHeight();
175 float maxLon = minLon + del_lon;
176 float maxLat = minLat + del_lat;
177
178 float lonDiff = maxLon - minLon;
179 float lonCenter = minLon + (maxLon - minLon)/2;
180 if (lonDiff > 180f) {
181 lonCenter += 180f;
182 }
183 float latCenter = minLat + (maxLat - minLat)/2;
184
185 cs = new LambertAzimuthalEqualArea(RealTupleType.SpatialEarth2DTuple, earthRadius,
186 lonCenter*Data.DEGREES_TO_RADIANS, latCenter*Data.DEGREES_TO_RADIANS,
187 0,0);
188
189 float[][] xy = cs.fromReference(new float[][] {{minLon,maxLon,minLon,maxLon},
190 {minLat,minLat,maxLat,maxLat}});
191
192
193 float min_x = Float.MAX_VALUE;
194 float min_y = Float.MAX_VALUE;
195 float max_x = Float.MIN_VALUE;
196 float max_y = Float.MIN_VALUE;
197
198 for (int k=0; k<xy[0].length;k++) {
199 if (xy[0][k] < min_x) min_x = xy[0][k];
200 if (xy[1][k] < min_y) min_y = xy[1][k];
201 if (xy[0][k] > max_x) max_x = xy[0][k];
202 if (xy[1][k] > max_y) max_y = xy[1][k];
203 }
204
205 float del_x = max_x - min_x;
206 float del_y = max_y - min_y;
207
208 if (forceSquareMapArea) {
209 if (del_x < del_y) {
210 del_x = del_y;
211 }
212 else if (del_y < del_x) {
213 del_y = del_x;
214 }
215 }
216
217 min_x = -del_x/2;
218 min_y = -del_y/2;
219
220 rect = new Rectangle2D.Float(min_x, min_y, del_x, del_y);
221 }
222
223 public Rectangle2D getDefaultMapArea() {
224 return rect;
225 }
226
227 public float[][] toReference(float[][] values) throws VisADException {
228 return cs.toReference(values);
229 }
230
231 public float[][] fromReference(float[][] values) throws VisADException {
232 return cs.fromReference(values);
233 }
234
235 public double[][] toReference(double[][] values) throws VisADException {
236 return cs.toReference(values);
237 }
238
239 public double[][] fromReference(double[][] values) throws VisADException {
240 return cs.fromReference(values);
241 }
242
243 public boolean equals(Object cs) {
244 if ( cs instanceof LambertAEA ) {
245 LambertAEA that = (LambertAEA) cs;
246 if ( (this.cs.equals(that.cs)) && this.getDefaultMapArea().equals(that.getDefaultMapArea())) {
247 return true;
248 }
249 }
250 return false;
251 }
252
253 }