/* ********************************************************************** * * Ranching Systems Group * Texas Agricultural Experiment Station * Department of Rangeland Ecology and Management * Mail Stop 212 * College Station, TX 77801 * * Copyright (C) 2000 * This software is subject to copyright protection under the laws of * the United States and other countries. * * ********************************************************************** * Fri Feb 4 10:20:34 CST 2000 Dan Schmitt (creation) * ********************************************************************** */ package com.bbn.openmap.layer.nexrad; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; import java.util.Properties; import java.util.StringTokenizer; import com.bbn.openmap.layer.OMGraphicHandlerLayer; import com.bbn.openmap.omGraphics.OMGraphic; import com.bbn.openmap.omGraphics.OMGraphicList; import com.bbn.openmap.omGraphics.OMPoly; import com.bbn.openmap.util.ColorFactory; import com.bbn.openmap.util.Debug; /** * Implement a Layer that displays nexrad rainfall data. * <p><pre> * * # zero value color (ARGB) * nexrad.color.bg=ffb3b3b3 * # max value color (ARGB) * nexrad.color.fg=ff000000 * # max rainfall value * nexrad.rain.max=6000 * # min rainfall value * nexrad.rain.min=0 * # URL for data file * nexrad.url=http://a.b.gov/file * * </pre> * <p> * NOTE: the color properties do not support alpha value if running on JDK 1.1. */ public class NexradLayer extends OMGraphicHandlerLayer { // property keys public final static transient String plotColorProperty = ".color.plot"; public final static transient String fontProperty = ".font"; public final static transient String maxRainProperty = ".rain.max"; public final static transient String minRainProperty = ".rain.min"; public final static transient String dataURLProperty = ".url"; // properties protected Color plotColor = new Color(0, 0, 200); protected int maxRain = 1000; protected int minRain = 0; protected URL dataURL = null; protected Font legendFont = Font.decode("SanSerif"); /** * Construct the DateLayer. */ public NexradLayer() { setName("Nexrad"); } /** * Sets the properties for the <code>Layer</code>. * * @param prefix the token to prefix the property names * @param props the <code>Properties</code> object */ public void setProperties(String prefix, Properties props) { super.setProperties(prefix, props); plotColor = ColorFactory.parseColorFromProperties(props, prefix + plotColorProperty, "0000C8"); String tmpMaxRain = props.getProperty(prefix + maxRainProperty); if (tmpMaxRain != null) { try { maxRain = Integer.valueOf(tmpMaxRain).intValue(); } catch (NumberFormatException e) { maxRain = 1000; } } String tmpMinRain = props.getProperty(prefix + minRainProperty); if (tmpMinRain != null) { try { minRain = Integer.valueOf(tmpMinRain).intValue(); } catch (NumberFormatException e) { minRain = 0; } } try { dataURL = new URL(props.getProperty(prefix + dataURLProperty)); loadData(dataURL); } catch (java.net.MalformedURLException e) { dataURL = null; } legendFont = Font.decode(props.getProperty(prefix + fontProperty)); } public void loadData(URL theDataStream) { try { BufferedReader f = new BufferedReader(new InputStreamReader(theDataStream.openStream())); StringTokenizer tok = new StringTokenizer(f.readLine()); int ulhrapx = (new Integer(tok.nextToken())).intValue(); int ulhrapy = (new Integer(tok.nextToken())).intValue(); int maxx = (new Integer(tok.nextToken())).intValue(); int maxy = (new Integer(tok.nextToken())).intValue(); int rain[][] = new int[maxx][maxy]; if (Debug.debugging("nexrad")) { Debug.output("NexradLayer: Reading " + theDataStream + " " + maxx + " " + maxy); } for (int any = 0; any < maxy; any++) { tok = new StringTokenizer(f.readLine()); for (int anx = 0; anx < maxx; anx++) { rain[anx][any] = (new Integer(tok.nextToken())).intValue(); } } f.close(); if (Debug.debugging("nexrad")) { Debug.output("NexradLayer: Completed " + theDataStream + " " + maxx + " " + maxy); } setList(createGraphics(ulhrapx, ulhrapy, maxx, maxy, rain)); // } catch (java.io.IOException oops) { } catch (Exception oops) { Debug.error("NexradLayer.loadData: Failed to read " + theDataStream); oops.printStackTrace(); } } public OMGraphicList createGraphics(int ulhrapx, int ulhrapy, int xcount, int ycount, int rain[][]) { OMGraphicList graphics = new OMGraphicList(); double ul[] = { 0, 0 }; double ur[] = { 0, 0 }; double ll[] = { 0, 0 }; double lr[] = { 0, 0 }; for (int x = 0; x < xcount; x++) { ll = hrap2lonlat(ulhrapx + x, ulhrapy); lr = hrap2lonlat(ulhrapx + x + 1, ulhrapy); for (int y = 0; y < ycount; y++) { ul = ll; ur = lr; ll = hrap2lonlat(ulhrapx + x, ulhrapy + y + 1); lr = hrap2lonlat(ulhrapx + x + 1, ulhrapy + y + 1); if (rain[x][y] > 0) { if (Debug.debugging("nexrad")) { Debug.output("NexradLayer: Rain " + rain[x][y] + " " + x + " " + y); } double polypoints[] = { ul[0], ul[1], ur[0], ur[1], lr[0], lr[1], ll[0], ll[1], ul[0], ul[1] }; OMPoly poly = new OMPoly(polypoints, OMGraphic.DECIMAL_DEGREES, OMGraphic.LINETYPE_STRAIGHT); Color plotc = scaledColor(rain[x][y]); poly.setFillPaint(plotc); poly.setLinePaint(plotc); graphics.add(poly); } } } return graphics; } /** * Paints the layer. * * @param g the Graphics context for painting */ public void paint(Graphics g) { super.paint(g); plotScale(g); } public void plotScale(Graphics g) { g.setColor(Color.red); int nameMin = 1; Font tmpFont = g.getFont(); g.setFont(legendFont); g.drawString(maxRain + " mm", 30, 30); g.drawString(nameMin + " mm", 30, 450); g.setFont(tmpFont); int range = 430; for (int k = 0; k <= range; k += 5) { g.setColor(scaledColor(minRain + (k * (maxRain - minRain) / range))); g.fillRect(10, 450 - k, 10, 5); } } public Color scaledColor(int value) { int alphaValue = 15 * value / maxRain; if (alphaValue > 15) alphaValue = 15; if (alphaValue < 0) alphaValue = 0; alphaValue *= 10; alphaValue += 55; return (new Color(plotColor.getRed(), plotColor.getGreen(), plotColor.getBlue(), alphaValue)); } public double[] hrap2lonlat(int xhrap, int yhrap) { float mesh = 4762.5f; float earthr = 6371200.0f; float stlond = -105.0f; float stlatd = 60.0f; float x = (xhrap - 401.0f) * mesh; float y = (yhrap - 1601.0f) * mesh; float arg = (float) (Math.pow(Math.pow(x, 2.0) + Math.pow(y, 2.0), 0.5) / (earthr * (1 + Math.sin(Math.toRadians(stlatd))))); float latd = 90.0f - 2.0f * (float) Math.toDegrees(Math.atan(arg)); float ang = (float) Math.toDegrees(Math.atan2(y, x)); if (y > 0) { ang = 270.0f - stlond - ang; } else { ang = -90.0f - stlond - ang; } float lond = 0f; if (ang < 180) { lond = -1.0f * ang; } else { lond = 360.0f - ang; } double res[] = { latd, lond }; return res; } }