Java tutorial
/* * Copyright (C) 2015 by Array Systems Computing Inc. http://www.array.ca * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.s1tbx.ocean.worldwind.layers; import com.bc.ceres.core.ProgressMonitor; import gov.nasa.worldwind.WorldWind; import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.awt.WorldWindowGLCanvas; import gov.nasa.worldwind.event.SelectEvent; import gov.nasa.worldwind.geom.Angle; import gov.nasa.worldwind.geom.LatLon; import gov.nasa.worldwind.geom.Position; import gov.nasa.worldwind.geom.Sector; import gov.nasa.worldwind.render.BasicShapeAttributes; import gov.nasa.worldwind.render.DrawContext; import gov.nasa.worldwind.render.Material; import gov.nasa.worldwind.render.Path; import gov.nasa.worldwind.render.Polyline; import gov.nasa.worldwind.render.Renderable; import gov.nasa.worldwind.render.ScreenAnnotation; import gov.nasa.worldwind.render.ShapeAttributes; import gov.nasa.worldwind.util.BufferFactory; import gov.nasa.worldwind.util.BufferWrapper; import gov.nasa.worldwind.util.WWMath; import gov.nasa.worldwindx.examples.analytics.AnalyticSurface; import gov.nasa.worldwindx.examples.analytics.AnalyticSurfaceAttributes; import gov.nasa.worldwindx.examples.util.DirectedPath; import org.apache.commons.math3.util.FastMath; import org.esa.s1tbx.ocean.toolviews.polarview.OceanSwellTopComponent; import org.esa.snap.core.datamodel.Band; import org.esa.snap.core.datamodel.GeoPos; import org.esa.snap.core.datamodel.MetadataElement; import org.esa.snap.core.datamodel.PixelPos; import org.esa.snap.core.datamodel.Product; import org.esa.snap.core.util.SystemUtils; import org.esa.snap.engine_utilities.datamodel.AbstractMetadata; import org.esa.snap.rcp.SnapApp; import org.esa.snap.worldwind.ArrowInfo; import org.esa.snap.worldwind.ColorBarLegend; import org.esa.snap.worldwind.ProductRenderablesInfo; import org.esa.snap.worldwind.layers.BaseLayer; import org.esa.snap.worldwind.layers.WWLayer; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.DecimalFormat; import java.text.Format; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; /** S-1 L2 OCN visualization */ public class Level2ProductLayer extends BaseLayer implements WWLayer { private static double HUE_BLUE = 240d / 360d; private static double HUE_RED = 0d / 360d; private static double HUE_MAX_RED = 1.0; private JPanel theControlLevel2Panel; private boolean theOWILimitChanged = false; private boolean theRVLLimitChanged = false; private boolean theOWIArrowsDisplayed = false; private static double GLOBE_RADIUS = 6371000; // this is the dimension of the cell in which to draw an arrow // at the highest resolution private static int theOWIArrowCellSize = 4; // the number of resolutions for OWI arrows private static int theOWIArrowNumLevels = 5; private JCheckBox theArrowsCB; //public double theCurrMinHue; //public double theCurrMaxHue; //private AnalyticSurface analyticSurface = null; //private BufferWrapper analyticSurfaceValueBuffer = null; private final HashMap<String, ColorBarLegend> theColorBarLegendHash = new HashMap<>(); // product associated with the current colorBar legend //private Product theColorBarLegendProduct = null; private String theSelectedComp = null; private final HashMap<Object, String> theObjectInfoHash = new HashMap<>(); private final HashMap<Object, Product> theSurfaceProductHash = new HashMap<>(); private final HashMap<Object, Integer> theSurfaceSequenceHash = new HashMap<>(); private final HashMap<Product, ProductRenderablesInfo> theProductRenderablesInfoHash = new HashMap<>(); //public ShapeAttributes dpAttrs = null; //public ShapeAttributes dpHighlightAttrs = null; public ScreenAnnotation theInfoAnnotation; private DirectedPath theLastSelectedDP = null; // this is set every time a product is added // because we can't added it in constructor as it is not called explicitly // and removeProduct needs it for redrawNow // (removeProduct can't be modified either to accept a wwd parameter) private WorldWindowGLCanvas theWWD; public Level2ProductLayer() { this.setName("S-1 Level-2 OCN"); theWWD = null; //dpHighlightAttrs = new BasicShapeAttributes(); //dpHighlightAttrs.setOutlineMaterial(Material.WHITE); //dpHighlightAttrs.setOutlineWidth(2d); // this is copied from gov.nasa.worldwindx.examples.util.LayerManagerLayer theInfoAnnotation = new ScreenAnnotation("", new Point(120, 520)); // Set annotation so that it will not force text to wrap (large width) and will adjust it's width to // that of the text. A height of zero will have the annotation height follow that of the text too. theInfoAnnotation.getAttributes().setSize(new Dimension(Integer.MAX_VALUE, 0)); theInfoAnnotation.getAttributes().setAdjustWidthToText(AVKey.SIZE_FIT_TEXT); // Set appearance attributes theInfoAnnotation.getAttributes().setCornerRadius(0); //theInfoAnnotation.getAttributes().setFont(this.font); theInfoAnnotation.getAttributes().setHighlightScale(1); theInfoAnnotation.getAttributes().setTextColor(Color.WHITE); theInfoAnnotation.getAttributes().setBackgroundColor(new Color(0f, 0f, 0f, .5f)); theInfoAnnotation.getAttributes().setInsets(new Insets(6, 6, 6, 6)); theInfoAnnotation.getAttributes().setBorderWidth(1); theInfoAnnotation.getAttributes().setVisible(false); } public void updateInfoAnnotation(final SelectEvent event) { //SystemUtils.LOG.info("updateInfoAnnotation " + event.getTopObject() + " " + theObjectInfoHash.get(event.getTopObject())); if (event.getEventAction().equals(SelectEvent.ROLLOVER) && theObjectInfoHash.get(event.getTopObject()) != null) { String info = theObjectInfoHash.get(event.getTopObject()); if (event.getTopObject() instanceof DirectedPath) { //SystemUtils.LOG.info("DirectedPath:::"); DirectedPath dp = (DirectedPath) event.getTopObject(); //dp.getAttributes().setOutlineMaterial(Material.WHITE); dp.setHighlighted(true); //dp.setAttributes(productLayer.dpHighlightAttrs); //theSelectedObjectLabel.setText("" + productLayer.theObjectInfoHash.get(dp)); theLastSelectedDP = dp; } theInfoAnnotation.setText(info); theInfoAnnotation.getAttributes().setVisible(true); //SystemUtils.LOG.info("selectedProduct " + getSelectedProduct()); //final ExecCommand command = datApp.getCommandManager().getExecCommand("showPolarWaveView"); //command.execute(2); } else if (event.getEventAction().equals(SelectEvent.LEFT_CLICK) && theSurfaceProductHash.get(event.getTopObject()) != null && theSurfaceSequenceHash.get(event.getTopObject()) != null) { //SystemUtils.LOG.info("click " + event.getTopObject()); OceanSwellTopComponent.setOSWRecord(theSurfaceProductHash.get(event.getTopObject()), theSurfaceSequenceHash.get(event.getTopObject())); } else { if (theLastSelectedDP != null) { theLastSelectedDP.setHighlighted(false); } theInfoAnnotation.getAttributes().setVisible(false); //theSelectedObjectLabel.setText(""); } } public void addProduct(final Product product, final WorldWindowGLCanvas wwd) { if (!product.getProductType().equalsIgnoreCase("OCN")) { return; } // if the product has already been added, just return if (theProductRenderablesInfoHash.get(product) != null) { return; } this.theWWD = wwd; addRenderable(theInfoAnnotation); final String text = "First line<br />Second line"; theInfoAnnotation.setText(text); theInfoAnnotation.getAttributes().setVisible(false); //theColorBarLegendProduct = product; final ProductRenderablesInfo productRenderablesInfo = new ProductRenderablesInfo(); // There is code in LayerMagerLayer that updates the size // it's re-rendered // Update current size and adjust annotation draw offset according to it's width //this.size = theInfoAnnotation.getPreferredSize(dc); //this.annotation.getAttributes().setDrawOffset(new Point(this.size.width / 2, 0)); //SystemUtils.LOG.info("product " + product.getName()); String prefix = "vv"; if (product.getBand(prefix + "_001_owiLon") == null) { prefix = "hh"; } MetadataElement metadataRoot = product.getMetadataRoot(); MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); String acquisitionMode = absRoot.getAttributeString(AbstractMetadata.ACQUISITION_MODE); final Band owiLonBand = product.getBand(prefix + "_001_owiLon"); final Band owiLatBand = product.getBand(prefix + "_001_owiLat"); final Band owiIncAngleBand = product.getBand(prefix + "_001_owiIncidenceAngle"); final Band owiWindSpeedBand = product.getBand(prefix + "_001_owiWindSpeed"); final Band owiWindDirBand = product.getBand(prefix + "_001_owiWindDirection"); int numRVLElements = 0; int rvlSwathWidth = 0; int rvlSwathHeight = 0; int numSwaths = 0; if (acquisitionMode.equalsIgnoreCase("IW")) { numSwaths = 3; } else if (acquisitionMode.equalsIgnoreCase("EW")) { numSwaths = 5; } for (int i = 0; i < numSwaths; i++) { Band rvlLonBand = product .getBand(prefix + "_001_" + acquisitionMode.toUpperCase() + (i + 1) + "_rvlLon"); numRVLElements += (rvlLonBand.getRasterWidth() * rvlLonBand.getRasterHeight()); rvlSwathWidth = rvlLonBand.getRasterWidth(); rvlSwathHeight = rvlLonBand.getRasterHeight(); } final GeoPos geoPos1 = product.getSceneGeoCoding().getGeoPos(new PixelPos(0, 0), null); final GeoPos geoPos2 = product.getSceneGeoCoding().getGeoPos( new PixelPos(product.getSceneRasterWidth() - 1, product.getSceneRasterHeight() - 1), null); try { if (owiLonBand != null) { final double[] lonValues = new double[owiLonBand.getRasterWidth() * owiLonBand.getRasterHeight()]; owiLonBand.readPixels(0, 0, owiLonBand.getRasterWidth(), owiLonBand.getRasterHeight(), lonValues, ProgressMonitor.NULL); final double[] latValues = new double[owiLatBand.getRasterWidth() * owiLatBand.getRasterHeight()]; owiLatBand.readPixels(0, 0, owiLatBand.getRasterWidth(), owiLatBand.getRasterHeight(), latValues, ProgressMonitor.NULL); final double[] incAngleValues = new double[owiIncAngleBand.getRasterWidth() * owiIncAngleBand.getRasterHeight()]; owiIncAngleBand.readPixels(0, 0, owiIncAngleBand.getRasterWidth(), owiIncAngleBand.getRasterHeight(), incAngleValues, ProgressMonitor.NULL); final double[] windSpeedValues = new double[owiWindSpeedBand.getRasterWidth() * owiWindSpeedBand.getRasterHeight()]; owiWindSpeedBand.readPixels(0, 0, owiWindSpeedBand.getRasterWidth(), owiWindSpeedBand.getRasterHeight(), windSpeedValues, ProgressMonitor.NULL); final double[] windDirValues = new double[owiWindDirBand.getRasterWidth() * owiWindDirBand.getRasterHeight()]; owiWindDirBand.readPixels(0, 0, owiWindDirBand.getRasterWidth(), owiWindDirBand.getRasterHeight(), windDirValues, ProgressMonitor.NULL); addWindSpeedArrows(latValues, lonValues, incAngleValues, windSpeedValues, windDirValues, owiLonBand.getRasterWidth(), owiLonBand.getRasterHeight(), productRenderablesInfo.theRenderableListHash.get("owi")); createColorSurfaceWithGradient(geoPos1, geoPos2, latValues, lonValues, windSpeedValues, owiWindSpeedBand.getRasterWidth(), owiWindSpeedBand.getRasterHeight(), 0, 10, false, productRenderablesInfo.theRenderableListHash.get("owi"), productRenderablesInfo, "owi"); } // right now, this happens: InvalidRangeException when reading variable rvlLon if (numRVLElements > 0) { boolean displayAsOne = false; // with numRVLElements we get BufferOverflow exception // it works with 2 swaths: 2*125 *233 double[] rvlLonValues = null; double[] rvlLatValues = null; double[] rvlRadVelValues = null; if (displayAsOne) { rvlLonValues = new double[numRVLElements]; rvlLatValues = new double[numRVLElements]; rvlRadVelValues = new double[numRVLElements]; } for (int i = 0; i < numSwaths; i++) { Band currRVLLonBand = product .getBand(prefix + "_001_" + acquisitionMode.toUpperCase() + (i + 1) + "_rvlLon"); Band currRVLLatBand = product .getBand(prefix + "_001_" + acquisitionMode.toUpperCase() + (i + 1) + "_rvlLat"); Band currRVLRadVelBand = product .getBand(prefix + "_001_" + acquisitionMode.toUpperCase() + (i + 1) + "_rvlRadVel"); double[] currRVLLonValues = new double[currRVLLonBand.getRasterWidth() * currRVLLonBand.getRasterHeight()]; currRVLLonBand.readPixels(0, 0, currRVLLonBand.getRasterWidth(), currRVLLonBand.getRasterHeight(), currRVLLonValues, ProgressMonitor.NULL); double[] currRVLLatValues = new double[currRVLLatBand.getRasterWidth() * currRVLLatBand.getRasterHeight()]; currRVLLatBand.readPixels(0, 0, currRVLLatBand.getRasterWidth(), currRVLLatBand.getRasterHeight(), currRVLLatValues, ProgressMonitor.NULL); double[] currRVLRadVelValues = new double[currRVLRadVelBand.getRasterWidth() * currRVLRadVelBand.getRasterHeight()]; currRVLRadVelBand.readPixels(0, 0, currRVLRadVelBand.getRasterWidth(), currRVLRadVelBand.getRasterHeight(), currRVLRadVelValues, ProgressMonitor.NULL); if (displayAsOne) { System.arraycopy(currRVLLonValues, 0, rvlLonValues, i * currRVLLonBand.getRasterWidth() * currRVLLonBand.getRasterHeight(), currRVLLonBand.getRasterWidth() * currRVLLonBand.getRasterHeight()); System.arraycopy(currRVLLatValues, 0, rvlLatValues, i * currRVLLatBand.getRasterWidth() * currRVLLatBand.getRasterHeight(), currRVLLatBand.getRasterWidth() * currRVLLatBand.getRasterHeight()); System.arraycopy(currRVLRadVelValues, 0, rvlRadVelValues, i * currRVLRadVelBand.getRasterWidth() * currRVLRadVelBand.getRasterHeight(), currRVLRadVelBand.getRasterWidth() * currRVLRadVelBand.getRasterHeight()); } else { createColorSurfaceWithGradient(geoPos1, geoPos2, currRVLLatValues, currRVLLonValues, currRVLRadVelValues, rvlSwathWidth, rvlSwathHeight, -6, 6, true, productRenderablesInfo.theRenderableListHash.get("rvl"), productRenderablesInfo, "rvl"); } } if (displayAsOne) { createColorSurfaceWithGradient(geoPos1, geoPos2, rvlLatValues, rvlLonValues, rvlRadVelValues, numSwaths * rvlSwathWidth, rvlSwathHeight, -6, 6, true, productRenderablesInfo.theRenderableListHash.get("rvl"), productRenderablesInfo, "rvl"); //createColorSurfaceWithGradient(geoPos1, geoPos2, rvlLatValues, rvlLonValues, rvlRadVelValues, 10, 10, -6, 6, true, productRenderablesInfo.theRenderableListHash.get("rvl"), productRenderablesInfo, "rvl"); } } double[][] oswData = null; double[][] owiData = null; double[][] rvlData = null; if (acquisitionMode.equalsIgnoreCase("WV") && metadataRoot.getElement("Original_Product_Metadata") != null && metadataRoot.getElement("Original_Product_Metadata").getElement("annotation") != null) { int numElements = metadataRoot.getElement("Original_Product_Metadata").getElement("annotation") .getNumElements(); if (numElements > 0) { oswData = new double[5][numElements]; owiData = new double[3][numElements]; rvlData = new double[3][numElements]; int i = 0; for (MetadataElement element : metadataRoot.getElement("Original_Product_Metadata") .getElement("annotation").getElements()) { oswData[0][i] = getData(element.getElement("oswLat")); oswData[1][i] = getData(element.getElement("oswLon")); oswData[2][i] = getData(element.getElement("oswHs")); oswData[3][i] = getData(element.getElement("oswWl")); oswData[4][i] = getData(element.getElement("oswDirmet")); owiData[0][i] = getData(element.getElement("owiLat")); owiData[1][i] = getData(element.getElement("owiLon")); owiData[2][i] = getData(element.getElement("owiWindSpeed")); rvlData[0][i] = getData(element.getElement("rvlLat")); rvlData[1][i] = getData(element.getElement("rvlLon")); rvlData[2][i] = getData(element.getElement("rvlRadVel")); i++; } } } if (oswData != null) { addWaveLengthArrows(oswData[0], oswData[1], oswData[3], oswData[4], productRenderablesInfo.theRenderableListHash.get("osw")); createWVColorSurfaceWithGradient(product, oswData[0], oswData[1], oswData[2], productRenderablesInfo.theRenderableListHash.get("osw"), "osw"); } //owiLonBand if (owiData != null && owiLonBand == null) { //addWaveLengthArrows(owiData[0], owiData[1], owiData[3], owiData[4], productRenderablesInfo.theRenderableListHash.get("owi")); createWVColorSurfaceWithGradient(product, owiData[0], owiData[1], owiData[2], productRenderablesInfo.theRenderableListHash.get("owi"), "owi"); } if (rvlData != null && numRVLElements == 0) { createWVColorSurfaceWithGradient(product, rvlData[0], rvlData[1], rvlData[2], productRenderablesInfo.theRenderableListHash.get("rvl"), "rvl"); } theProductRenderablesInfoHash.put(product, productRenderablesInfo); if (theControlLevel2Panel != null) { theControlLevel2Panel.setVisible(true); } setComponentVisible(theSelectedComp, wwd); } catch (Exception e) { SnapApp.getDefault().handleError("L2ProductLayer unable to add product " + product.getName(), e); } } public double getData(MetadataElement element) { if (element.getElement("Values") != null) { return element.getElement("Values").getAttribute("data").getData().getElemDouble(); } return 0; } public void createColorSurfaceWithGradient(GeoPos geoPos1, GeoPos geoPos2, double[] latValues, double[] lonValues, double[] values, int width, int height, double minValue, double maxValue, boolean whiteZero, ArrayList<Renderable> renderableList, ProductRenderablesInfo prodRenderInfo, String comp) { createColorSurface(geoPos1, geoPos2, latValues, lonValues, values, width, height, renderableList, prodRenderInfo, comp); //createColorSurface(geoPos2.getLat(), geoPos1.getLat(), geoPos1.getLon(), geoPos2.getLon(), rvlRadVelValues, 40, 40, minValue, maxValue, renderableList); //theCurrMinHue = minHue; //theCurrMaxHue = maxHue; //createRandomColorSurface(25, 35, -110, -100, HUE_BLUE, HUE_RED, 40, 40, minValue, maxValue, this); //createRandomColorSurface(geoPos2.getLat(), geoPos1.getLat(), 55, 57, HUE_BLUE, HUE_RED, 40, 40, minValue, maxValue, this); // don't create color legend if one already exists if (theColorBarLegendHash.get(comp) != null) { // use the existing limits minValue = theColorBarLegendHash.get(comp).getMinValue(); maxValue = theColorBarLegendHash.get(comp).getMaxValue(); } createColorGradient(minValue, maxValue, whiteZero, prodRenderInfo, comp); } public void createColorBarLegend(double minValue, double maxValue, String title, String comp) { //SystemUtils.LOG.info("createColorBarLegend " + minValue + " " + maxValue); String unit = "m/s"; if (comp.equalsIgnoreCase("osw")) { unit = "m"; } final Format legendLabelFormat = new DecimalFormat("# " + unit); final ColorBarLegend colorBarLegend = new ColorBarLegend(); colorBarLegend.setColorGradient(32, 256, minValue, maxValue, HUE_RED, HUE_MAX_RED, Color.WHITE, ColorBarLegend.createDefaultColorGradientLabels(minValue, maxValue, legendLabelFormat), ColorBarLegend.createDefaultTitle(title), comp.equalsIgnoreCase("rvl")); /* colorBarLegend = ColorBarLegend.fromColorGradient(32, 256, minValue, maxValue, minHue, maxHue, Color.WHITE, ColorBarLegend.createDefaultColorGradientLabels(minValue, maxValue, legendLabelFormat), ColorBarLegend.createDefaultTitle(title), whiteZero); */ colorBarLegend.setOpacity(0.8); colorBarLegend.setScreenLocation(new Point(900, 320)); //addRenderable(colorBarLegend); theColorBarLegendHash.put(comp, colorBarLegend); } public void setComponentVisible(String comp, WorldWindowGLCanvas wwd) { //SystemUtils.LOG.info("setComponentVisible " + comp); //SystemUtils.LOG.info("theColorBarLegendHash " + theColorBarLegendHash); for (String currComp : theColorBarLegendHash.keySet()) { if (theColorBarLegendHash.get(currComp) != null) { removeRenderable(theColorBarLegendHash.get(currComp)); if (currComp.equals(comp)) { addRenderable(theColorBarLegendHash.get(currComp)); } //ProductRenderablesInfo productRenderablesInfo = theProductRenderablesInfoHash.get(theColorBarLegendProduct); for (ProductRenderablesInfo productRenderablesInfo : theProductRenderablesInfoHash.values()) { //SystemUtils.LOG.info("::: productRenderablesInfo " + productRenderablesInfo); if (productRenderablesInfo != null) { ArrayList<Renderable> renderableList = productRenderablesInfo.theRenderableListHash .get(currComp); for (Renderable renderable : renderableList) { removeRenderable(renderable); if (currComp.equals(comp)) { addRenderable(renderable); } } } } } } wwd.redrawNow(); } private void addWindSpeedArrows(double[] latValues, double[] lonValues, double[] incAngleValues, double[] windSpeedValues, double[] windDirValues, int width, int height, ArrayList<Renderable> renderableList) { double pixelWidth = Math.abs(lonValues[0] - lonValues[lonValues.length - 1]) / width; double pixelHeight = Math.abs(latValues[0] - latValues[latValues.length - 1]) / height; //SystemUtils.LOG.info("pixelWidth " + pixelWidth + " pixelHeight " + pixelHeight); //System.out.println("pixelWidth " + pixelWidth + " pixelHeight " + pixelHeight); // take the smaller dimension double arrowLength_deg = pixelWidth; if (pixelHeight < pixelWidth) { arrowLength_deg = pixelHeight; } arrowLength_deg = arrowLength_deg * theOWIArrowCellSize; // let the arrow head be approximately one third of the whole length double arrowHeadLength = Angle.fromDegrees(arrowLength_deg).radians * GLOBE_RADIUS / 3; final ShapeAttributes dpAttrs = new BasicShapeAttributes(); dpAttrs.setOutlineMaterial(Material.BLACK); dpAttrs.setOutlineWidth(2d); //int numCellRows = (int) Math.ceil((height / cellSize)); //int numCellCols = (int) Math.ceil((width / cellSize)); int numCellRows = height / theOWIArrowCellSize; int numCellCols = width / theOWIArrowCellSize; //SystemUtils.LOG.info(":: numCells: " + numCellRows + " " + numCellCols); // we need to add 1 because if height is not divisible by cellSize then (height / cellSize) is equal // to (height-1) / cellSize so the last element is [numCellRows] // (this same argument applies to width) // Still, we'll keep numCellRows and numCellCols as limits when we iterate // through it and disregard this possible last element (which is the remainder, in the corners of the whole area) ArrowInfo[][][] arrowGrid = new ArrowInfo[theOWIArrowNumLevels][numCellRows + 1][numCellCols + 1]; for (int row = 0; row < height; row = row + theOWIArrowCellSize) { for (int col = 0; col < width; col = col + theOWIArrowCellSize) { //int i = row*width + col; int globalInd = row * width + col; float avgLat = 0; float avgLon = 0; double avgIncAngle = 0; double avgWindSpeed = 0; double avgWindDir = 0; int finalCellRow = row + theOWIArrowCellSize; int finalCellCol = col + theOWIArrowCellSize; if (finalCellRow > height) { finalCellRow = height; } if (finalCellCol > width) { finalCellCol = width; } for (int currCellRow = row; currCellRow < finalCellRow; currCellRow++) { for (int currCellCol = col; currCellCol < finalCellCol; currCellCol++) { int i = currCellRow * width + currCellCol; avgLat += latValues[i]; avgLon += lonValues[i]; avgIncAngle += incAngleValues[i]; avgWindSpeed += windSpeedValues[i]; avgWindDir += windDirValues[i]; } } avgLat = avgLat / ((finalCellRow - row) * (finalCellCol - col)); avgLon = avgLon / ((finalCellRow - row) * (finalCellCol - col)); avgIncAngle = avgIncAngle / ((finalCellRow - row) * (finalCellCol - col)); avgWindSpeed = avgWindSpeed / ((finalCellRow - row) * (finalCellCol - col)); avgWindDir = avgWindDir / ((finalCellRow - row) * (finalCellCol - col)); /* avgLat = latValues[globalInd]; avgLon = lonValues[globalInd]; avgWindDir = windDirValues[globalInd]; */ /* System.out.println("avgLat " + avgLat); System.out.println("avgLon " + avgLon); System.out.println("avgWindDir " + avgWindDir); */ //System.out.println("avgIncAngle " + avgIncAngle); //for (int i = 0; i < latValues.length; i=i+50) { //System.out.println(lonValues[i] + "::==::" + latValues[i] + "::==::" + incAngleValues[i] + "::==::" + windSpeedValues[i] + "::==::" + windDirValues[i] + "::==::"); final Position startPos = new Position(Angle.fromDegreesLatitude(avgLat), Angle.fromDegreesLongitude(avgLon), 10.0); final Position endPos = new Position(LatLon.greatCircleEndPosition(startPos, Angle.fromDegrees(avgWindDir), Angle.fromDegrees(arrowLength_deg)), 10.0); //System.out.println("startPos " + startPos + " endPos " + endPos); final ArrayList<Position> positions = new ArrayList<>(); positions.add(startPos); positions.add(endPos); final DirectedPath directedPath = getDirectedPath(positions, dpAttrs); //double arrowHeadLength = computeSegmentLength(directedPath, dc, startPos, endPos) / 4; directedPath.setArrowLength(arrowHeadLength); int currCellRow = row / theOWIArrowCellSize; int currCellCol = col / theOWIArrowCellSize; //SystemUtils.LOG.info(":: currCell: " + currCellRow + " " + currCellCol); arrowGrid[0][currCellRow][currCellCol] = new ArrowInfo(directedPath, avgIncAngle, avgWindSpeed, avgWindDir, arrowLength_deg); //if (currCellRow > 0 && currCellCol > 0) { for (int cellSizeResolution = 1; cellSizeResolution < theOWIArrowNumLevels; cellSizeResolution++) { // treating the original cell size as 1 int currBigCellSize = (int) FastMath.pow(2, cellSizeResolution); if ((currCellRow % currBigCellSize == currBigCellSize - 1) && (currCellCol % currBigCellSize == currBigCellSize - 1)) { int bigCellRow = (currCellRow / currBigCellSize); int bigCellCol = (currCellCol / currBigCellSize); int smallCellStartRow = bigCellRow * 2; int smallCellStartCol = bigCellCol * 2; double cumAvgIncAngle = 0; double cumAvgWindSpeed = 0; double cumAvgWindDir = 0; Position cumStartPos = new Position(Angle.fromDegreesLatitude(0.0), Angle.fromDegreesLongitude(0.0), 10.0); Position cumEndPos = new Position(Angle.fromDegreesLatitude(0.0), Angle.fromDegreesLongitude(0.0), 10.0); double cumStartPosLat_deg = 0; double cumStartPosLon_deg = 0; double bigCellArrowLength_deg = currBigCellSize * arrowLength_deg; for (int currSmallCellRow = smallCellStartRow; currSmallCellRow < smallCellStartRow + 2; currSmallCellRow++) { for (int currSmallCellCol = smallCellStartCol; currSmallCellCol < smallCellStartCol + 2; currSmallCellCol++) { ArrowInfo currSmallArrow = arrowGrid[cellSizeResolution - 1][currSmallCellRow][currSmallCellCol]; // all small cell's arrow length's will be the same //bigCellArrowLength_deg = 2*currSmallArrow.theArrowLength; cumAvgIncAngle += currSmallArrow.theAvgIncAngle; cumAvgWindSpeed += currSmallArrow.theAvgWindSpeed; cumAvgWindDir += currSmallArrow.theAvgWindDir; boolean firstPosNext = true; for (Position pos : currSmallArrow.theDirectedPath.getPositions()) { if (firstPosNext) { cumStartPos = cumStartPos.add(pos); cumStartPosLat_deg += pos.getLatitude().getDegrees(); cumStartPosLon_deg += pos.getLongitude().getDegrees(); firstPosNext = false; } else { cumEndPos = cumEndPos.add(pos); } } } } cumAvgIncAngle = cumAvgIncAngle / 4; cumAvgWindSpeed = cumAvgWindSpeed / 4; cumAvgWindDir = cumAvgWindDir / 4; cumStartPosLat_deg = cumStartPosLat_deg / 4; cumStartPosLon_deg = cumStartPosLon_deg / 4; arrowGrid[cellSizeResolution][bigCellRow][bigCellCol] = null; Position bigCellStartPos = new Position(Angle.fromDegreesLatitude(cumStartPosLat_deg), Angle.fromDegreesLongitude(cumStartPosLon_deg), 10.0); Position bigCellEndPos = new Position(LatLon.greatCircleEndPosition(bigCellStartPos, Angle.fromDegrees(cumAvgWindDir), Angle.fromDegrees(bigCellArrowLength_deg)), 10.0); //System.out.println("startPos " + startPos + " endPos " + endPos); ArrayList<Position> bigCellPositions = new ArrayList<>(); bigCellPositions.add(bigCellStartPos); bigCellPositions.add(bigCellEndPos); DirectedPath bigDC = getDirectedPath(bigCellPositions, dpAttrs); bigDC.setArrowLength(currBigCellSize * arrowHeadLength); arrowGrid[cellSizeResolution][bigCellRow][bigCellCol] = new ArrowInfo(bigDC, cumAvgIncAngle, cumAvgWindSpeed, cumAvgWindDir, bigCellArrowLength_deg); } } //} } } for (int cellRow = 0; cellRow < numCellRows; cellRow++) { for (int cellCol = 0; cellCol < numCellCols; cellCol++) { final int finalCellRow = cellRow; final int finalCellCol = cellCol; //DirectedPath directedPath = arrowGrid[0][cellRow][cellCol].theDirectedPath; Renderable renderable = new Renderable() { public void render(DrawContext dc) { if (!theOWIArrowsDisplayed) { return; } // this is the length of the arrow head actually //double arrowHeadLength = computeSegmentLength(directedPath, dc, startPos, endPos) / 4; //directedPath.setArrowLength(arrowHeadLength); //double maxHeight = cellSize * 0.5e6 / 16; double currAlt = dc.getView().getCurrentEyePosition().getAltitude(); /* int selectedResolutionInd = 0; for (int resolutionInd = 0; resolutionInd < theOWIArrowNumLevels; resolutionInd++) { double maxResAlt = (0.5e6 / 4) * Math.pow(2,resolutionInd); double minResAlt = maxResAlt / 2; if (currAlt > minResAlt && currAlt < maxResAlt) { selectedResolutionInd = resolutionInd; break; } } */ int selectedResolutionInd = (int) (Math.log(currAlt * (4 / 0.5e6)) / Math.log(2)); if (selectedResolutionInd < 0) { selectedResolutionInd = 0; } else if (selectedResolutionInd > 4) { selectedResolutionInd = 4; } int selectedInd = (int) FastMath.pow(2, selectedResolutionInd); //int selectedInd = (int) (currAlt * (4 / 0.5e6)); if ((finalCellRow % selectedInd == 0) && (finalCellCol % selectedInd == 0)) { int bigCellRow = finalCellRow / selectedInd; int bigCellCol = finalCellCol / selectedInd; // this check is necessary because the possible last element which we disregarded and which is null if (arrowGrid[selectedResolutionInd][bigCellRow] != null && arrowGrid[selectedResolutionInd][bigCellRow][bigCellCol] != null) { ArrowInfo currArrow = arrowGrid[selectedResolutionInd][bigCellRow][bigCellCol]; // we won't render the arrow if the wind speed is zero if (currArrow.theAvgWindSpeed > 0) { DirectedPath currDirectedPath = currArrow.theDirectedPath; currDirectedPath.render(dc); if (theObjectInfoHash.get(currDirectedPath) == null) { String info = "Wind Speed: " + currArrow.theAvgWindSpeed + "<br/>"; info += "Wind Direction: " + currArrow.theAvgWindDir + "<br/>"; info += "Incidence Angle: " + currArrow.theAvgIncAngle + "<br/>"; theObjectInfoHash.put(currDirectedPath, info); } } } } /* if (currAlt > minHeight && currAlt < maxHeight) { directedPath.render(dc); //System.out.println("arrowHeadLength " + arrowHeadLength); } */ //System.out.println("eyePosition " + dc.getView().getCurrentEyePosition()); } }; addRenderable(renderable); if (renderableList != null) { renderableList.add(renderable); } } } } private DirectedPath getDirectedPath(ArrayList<Position> positions, ShapeAttributes dpAttrs) { DirectedPath directedPath = new DirectedPath(positions); directedPath.setAttributes(dpAttrs); //directedPath.setHighlightAttributes(highlightAttrs); directedPath.setVisible(true); directedPath.setFollowTerrain(true); directedPath.setAltitudeMode(WorldWind.RELATIVE_TO_GROUND); directedPath.setPathType(AVKey.GREAT_CIRCLE); return directedPath; } private void addWaveLengthArrows(double[] latValues, double[] lonValues, double[] waveLengthValues, double[] waveDirValues, ArrayList<Renderable> renderableList) { //SystemUtils.LOG.info(":: addWaveLengthArrows "); final ShapeAttributes dpAttrs = new BasicShapeAttributes(); dpAttrs.setOutlineMaterial(Material.WHITE); dpAttrs.setOutlineWidth(2d); for (int ind = 0; ind < waveLengthValues.length; ind++) { //int ind = row*width + col; double arrowLength_deg = waveLengthValues[ind] / 4000; //double arrowLength_deg = 0.277392578125; double arrowHeadLength = Angle.fromDegrees(arrowLength_deg).radians * GLOBE_RADIUS / 3; final Position startPos = new Position(Angle.fromDegreesLatitude(latValues[ind]), Angle.fromDegreesLongitude(lonValues[ind]), 10.0); final Position endPos = new Position(LatLon.greatCircleEndPosition(startPos, Angle.fromDegrees(waveDirValues[ind]), Angle.fromDegrees(arrowLength_deg)), 10.0); //System.out.println("waveLengthValues[i] " + waveLengthValues[i]); final ArrayList<Position> positions = new ArrayList<>(); positions.add(startPos); positions.add(endPos); DirectedPath directedPath = getDirectedPath(positions, dpAttrs); directedPath.setArrowLength(arrowHeadLength); Renderable renderable = new Renderable() { public void render(DrawContext dc) { directedPath.render(dc); } }; addRenderable(renderable); if (renderableList != null) { renderableList.add(renderable); } } } private void createWVColorSurfaceWithGradient(Product product, double[] latValues, double[] lonValues, double[] values, ArrayList<Renderable> renderableList, String comp) { //SystemUtils.LOG.info(":: createWVColorSurfaceWithGradient "); final ShapeAttributes dpAttrs = new BasicShapeAttributes(); dpAttrs.setOutlineMaterial(Material.WHITE); dpAttrs.setOutlineWidth(2d); // we cannot make it a scalar object because it has to be final and then we won't be able to assign to it // we'll store it as a first object of a final array //final ArrayList<Object> ctgSurfaceList = new ArrayList<Object>(); for (int ind = 0; ind < values.length; ind++) { final int finalInd = ind; final ArrayList<Position> polygonPositions = new ArrayList<>(); double vignette_half_side_deg = (180 / Math.PI) * 10000 / GLOBE_RADIUS; polygonPositions.add(new Position(Angle.fromDegreesLatitude(latValues[ind] - vignette_half_side_deg), Angle.fromDegreesLongitude(lonValues[ind] - vignette_half_side_deg), 10.0)); polygonPositions.add(new Position(Angle.fromDegreesLatitude(latValues[ind] - vignette_half_side_deg), Angle.fromDegreesLongitude(lonValues[ind] + vignette_half_side_deg), 10.0)); polygonPositions.add(new Position(Angle.fromDegreesLatitude(latValues[ind] + vignette_half_side_deg), Angle.fromDegreesLongitude(lonValues[ind] + vignette_half_side_deg), 10.0)); polygonPositions.add(new Position(Angle.fromDegreesLatitude(latValues[ind] + vignette_half_side_deg), Angle.fromDegreesLongitude(lonValues[ind] - vignette_half_side_deg), 10.0)); polygonPositions.add(new Position(Angle.fromDegreesLatitude(latValues[ind] - vignette_half_side_deg), Angle.fromDegreesLongitude(lonValues[ind] - vignette_half_side_deg), 10.0)); Polyline p = new Polyline(); p.setFollowTerrain(true); p.setPositions(polygonPositions); addRenderable(p); if (renderableList != null) { renderableList.add(p); } String info = ""; if (comp.equalsIgnoreCase("osw")) { info = "Wave Length: " + values[ind] + "<br/>"; } else if (comp.equalsIgnoreCase("owi")) { info = "Wind Speed: " + values[ind] + "<br/>"; } else if (comp.equalsIgnoreCase("rvl")) { info = "Radial Velocity: " + values[ind] + "<br/>"; } String finalInfo = info; //AnalyticSurface analyticSurface = new AnalyticSurface(); AnalyticSurface analyticSurface = new AnalyticSurface() { public void render(DrawContext dc) { super.render(dc); if (clampToGroundSurface != null) { theObjectInfoHash.put(clampToGroundSurface, finalInfo); theSurfaceProductHash.put(clampToGroundSurface, product); theSurfaceSequenceHash.put(clampToGroundSurface, finalInd); } } }; analyticSurface.setSector(Sector.fromDegrees(latValues[ind] - vignette_half_side_deg, latValues[ind] + vignette_half_side_deg, lonValues[ind] - vignette_half_side_deg, lonValues[ind] + vignette_half_side_deg)); analyticSurface.setAltitudeMode(WorldWind.CLAMP_TO_GROUND); // one by one square doesn't seem to work, so we'll just use the next smallest // possible square and repeat the same value 4 times analyticSurface.setDimensions(2, 2); final ArrayList<AnalyticSurface.GridPointAttributes> attributesList = new ArrayList<>(); for (int i = 0; i < 4; i++) { attributesList.add(createColorGradientAttributes(values[ind], 0, 10, HUE_RED, HUE_MAX_RED, false)); } analyticSurface.setValues(attributesList); AnalyticSurfaceAttributes attr = new AnalyticSurfaceAttributes(); attr.setDrawShadow(false); attr.setInteriorOpacity(1.0); //attr.setOutlineWidth(3); attr.setDrawOutline(false); analyticSurface.setSurfaceAttributes(attr); analyticSurface.setClientLayer(this); addRenderable(analyticSurface); if (renderableList != null) { renderableList.add(analyticSurface); } } } private double computeSegmentLength(Path path, DrawContext dc, Position posA, Position posB) { final LatLon llA = new LatLon(posA.getLatitude(), posA.getLongitude()); final LatLon llB = new LatLon(posB.getLatitude(), posB.getLongitude()); Angle ang; String pathType = path.getPathType(); if (pathType == AVKey.LINEAR) { ang = LatLon.linearDistance(llA, llB); } else if (pathType == AVKey.RHUMB_LINE || pathType == AVKey.LOXODROME) { ang = LatLon.rhumbDistance(llA, llB); } else { // Great circle ang = LatLon.greatCircleDistance(llA, llB); } if (path.getAltitudeMode() == WorldWind.CLAMP_TO_GROUND) { return ang.radians * (dc.getGlobe().getRadius()); } final double height = 0.5 * (posA.getElevation() + posB.getElevation()); return ang.radians * (dc.getGlobe().getRadius() + height * dc.getVerticalExaggeration()); } // ADDED protected void createColorSurface(GeoPos geoPos1, GeoPos geoPos2, double[] latValues, double[] lonValues, double[] vals, int width, int height, ArrayList<Renderable> renderableList, ProductRenderablesInfo prodRenderInfo, String comp) { //double minValue = -200e3; //double maxValue = 200e3; //SystemUtils.LOG.info("createColorSurface " + latValues.length + " " + lonValues.length + " " + vals.length + " " + width + " " + height); // analytic surface has to be overidden in order to allow for non-rectangular surfaces // the approach is render the surface point by point and not use the sector as the boundary AnalyticSurface analyticSurface = new AnalyticSurface() { protected void doUpdate(DrawContext dc) { this.referencePos = new Position(this.sector.getCentroid(), this.altitude); this.referencePoint = dc.getGlobe().computePointFromPosition(this.referencePos); if (this.surfaceRenderInfo == null || this.surfaceRenderInfo.getGridWidth() != this.width || this.surfaceRenderInfo.getGridHeight() != this.height) { this.surfaceRenderInfo = new RenderInfo(this.width, this.height) { public void drawInterior(DrawContext dc) { if (dc == null) { cartesianVertexBuffer.rewind(); geographicVertexBuffer.rewind(); colorBuffer.rewind(); shadowColorBuffer.rewind(); return; } super.drawInterior(dc); } }; } this.updateSurfacePoints(dc, this.surfaceRenderInfo); this.updateSurfaceNormals(this.surfaceRenderInfo); } protected void updateSurfacePoints(DrawContext dc, RenderInfo outRenderInfo) { Iterator<? extends GridPointAttributes> iter = this.values.iterator(); //int i = 0; //while (iter.hasNext()) { for (int row = 0; row < this.height; row++) { for (int col = 0; col < this.width; col++) { int i = row * (this.width) + col; GridPointAttributes attr = iter.hasNext() ? iter.next() : null; if (vals[i] != -999) { //if (vals[i] > 0) { this.updateNextSurfacePoint(dc, Angle.fromDegrees(latValues[i]), Angle.fromDegrees(lonValues[i]), attr, outRenderInfo); } //i++; } } //} //outRenderInfo.rewindBuffers(); outRenderInfo.drawInterior(null); } }; analyticSurface.setSector( Sector.fromDegrees(geoPos2.getLat(), geoPos1.getLat(), geoPos1.getLon(), geoPos2.getLon())); analyticSurface.setAltitudeMode(WorldWind.CLAMP_TO_GROUND); analyticSurface.setDimensions(width, height); AnalyticSurfaceAttributes attr = new AnalyticSurfaceAttributes(); attr.setDrawShadow(false); attr.setInteriorOpacity(1.0); //attr.setOutlineWidth(3); attr.setDrawOutline(false); analyticSurface.setSurfaceAttributes(attr); analyticSurface.setClientLayer(this); //addRenderable(analyticSurface); //analyticSurfaceValueBuffer = randomGridValues(width, height, minValue, maxValue); BufferWrapper analyticSurfaceValueBuffer = (new BufferFactory.DoubleBufferFactory()).newBuffer(vals.length); analyticSurfaceValueBuffer.putDouble(0, vals, 0, vals.length); //smoothValues(width, height, values, 0.5d); //scaleValues(values, values.length, minValue, maxValue); //mixValuesOverTime(2000L, firstBuffer, analyticSurfaceValueBuffer, minValue, maxValue, minHue, maxHue, analyticSurface); prodRenderInfo.setAnalyticSurfaceAndBuffer(analyticSurface, analyticSurfaceValueBuffer, comp); if (renderableList != null) { renderableList.add(analyticSurface); } } public void createColorGradient(double minValue, double maxValue, boolean whiteZero, ProductRenderablesInfo prodRenderInfo, String comp) { //SystemUtils.LOG.info("createColorGradient " + minValue + " " + maxValue + " " + comp); ArrayList<AnalyticSurface> analyticSurfaces = null; ArrayList<BufferWrapper> analyticSurfaceValueBuffers = null; if (comp.equalsIgnoreCase("owi")) { analyticSurfaces = prodRenderInfo.owiAnalyticSurfaces; analyticSurfaceValueBuffers = prodRenderInfo.owiAnalyticSurfaceValueBuffers; } else if (comp.equalsIgnoreCase("osw")) { analyticSurfaces = prodRenderInfo.oswAnalyticSurfaces; analyticSurfaceValueBuffers = prodRenderInfo.oswAnalyticSurfaceValueBuffers; } else if (comp.equalsIgnoreCase("rvl")) { analyticSurfaces = prodRenderInfo.rvlAnalyticSurfaces; analyticSurfaceValueBuffers = prodRenderInfo.rvlAnalyticSurfaceValueBuffers; } if (analyticSurfaces != null) { for (int currSurfInd = 0; currSurfInd < analyticSurfaces.size(); currSurfInd++) { AnalyticSurface analyticSurface = analyticSurfaces.get(currSurfInd); BufferWrapper analyticSurfaceValueBuffer = analyticSurfaceValueBuffers.get(currSurfInd); final ArrayList<AnalyticSurface.GridPointAttributes> attributesList = new ArrayList<>(); for (int i = 0; i < analyticSurfaceValueBuffer.length(); i++) { double d = analyticSurfaceValueBuffer.getDouble(i); attributesList.add( createColorGradientAttributes(d, minValue, maxValue, HUE_RED, HUE_MAX_RED, whiteZero)); } analyticSurface.setValues(attributesList); } } } // ADDED: // this method is copied from gov.nasa.worldwindx.examples.analytics.AnalyticSurface public static AnalyticSurface.GridPointAttributes createColorGradientAttributes(final double value, double minValue, double maxValue, double minHue, double maxHue, boolean whiteZero) { final double hueFactor = WWMath.computeInterpolationFactor(value, minValue, maxValue); //double hue = WWMath.mixSmooth(hueFactor, minHue, maxHue); final double hue = WWMath.mix(hueFactor, minHue, maxHue); double sat = 1.0; if (whiteZero) { sat = Math.abs(WWMath.mixSmooth(hueFactor, -1, 1)); } final Color color = Color.getHSBColor((float) hue, (float) sat, 1f); final double opacity = WWMath.computeInterpolationFactor(value, minValue, minValue + (maxValue - minValue) * 0.1); final Color rgbaColor = new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) (255 * opacity)); return AnalyticSurface.createGridPointAttributes(value, rgbaColor); } public void removeProduct(final Product product) { //SystemUtils.LOG.info(":: removeProduct " + product); //SystemUtils.LOG.info(":: theProductRenderablesInfoHash " + theProductRenderablesInfoHash); final ProductRenderablesInfo productRenderablesInfo = theProductRenderablesInfoHash.get(product); //SystemUtils.LOG.info(":: chosen ProductRenderablesInfo " + productRenderablesInfo); if (productRenderablesInfo != null) { //for (ProductRenderablesInfo currProductRenderablesInfo : theProductRenderablesInfoHash.values()) { //SystemUtils.LOG.info(":: currProductRenderablesInfo " + productRenderablesInfo); for (ArrayList<Renderable> renderableList : productRenderablesInfo.theRenderableListHash.values()) { //SystemUtils.LOG.info(":: renderableList " + renderableList); for (Renderable renderable : renderableList) { //SystemUtils.LOG.info(":: renderable " + renderable); removeRenderable(renderable); if (renderable instanceof DirectedPath) { theObjectInfoHash.remove(renderable); theSurfaceProductHash.remove(renderable); theSurfaceSequenceHash.remove(renderable); } } renderableList.clear(); } } /* for (ColorBarLegend legend : theColorBarLegendHash.values()) { removeRenderable(legend); } theColorBarLegendHash.clear(); */ theProductRenderablesInfoHash.remove(product); if (theProductRenderablesInfoHash.size() == 0) { theControlLevel2Panel.setVisible(false); for (ColorBarLegend colorBarLegend : theColorBarLegendHash.values()) { removeRenderable(colorBarLegend); } } theWWD.redrawNow(); //} theWWD.redrawNow(); } public void recreateColorBarAndGradient(double minValue, double maxValue, String comp, WorldWindowGLCanvas wwd, boolean redraw) { //SystemUtils.LOG.info("recreateColorBarAndGradient " + minValue + " " + maxValue + " " + comp + " " + theColorBarLegendHash.get(comp)); String title = ""; if (comp.equalsIgnoreCase("owi")) { title = "OWI Wind Speed"; } else if (comp.equalsIgnoreCase("osw")) { title = "OSW Wave Height."; } else if (comp.equalsIgnoreCase("rvl")) { title = "RVL Rad. Vel."; } if (redraw) { removeRenderable(theColorBarLegendHash.get(comp)); } createColorBarLegend(minValue, maxValue, title, comp); if (redraw) { addRenderable(theColorBarLegendHash.get(comp)); } for (ProductRenderablesInfo productRenderablesInfo : theProductRenderablesInfoHash.values()) { //createColorGradient(minValue, maxValue, false, theProductRenderablesInfoHash.get(theColorBarLegendProduct), comp); createColorGradient(minValue, maxValue, false, productRenderablesInfo, comp); } if (redraw) { wwd.redrawNow(); } } public JPanel getControlPanel(final WorldWindowGLCanvas wwd) { theControlLevel2Panel = new JPanel(new GridLayout(7, 1, 5, 5)); theControlLevel2Panel.setVisible(false); final JRadioButton owiBtn = new JRadioButton("OWI"); owiBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { theSelectedComp = "owi"; setComponentVisible("owi", wwd); theArrowsCB.setEnabled(true); } }); final JRadioButton oswBtn = new JRadioButton("OSW"); oswBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { theSelectedComp = "osw"; setComponentVisible("osw", wwd); theArrowsCB.setEnabled(false); //SystemUtils.LOG.info("theSurfaceProductHash " + theSurfaceProductHash); //SystemUtils.LOG.info("theSurfaceSequenceHash " + theSurfaceSequenceHash); } }); final JRadioButton rvlBtn = new JRadioButton("RVL"); rvlBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { theSelectedComp = "rvl"; //System.out.println("rvl:"); //setComponentVisible("owi", false, getWwd()); //setComponentVisible("osw", false, getWwd()); setComponentVisible("rvl", wwd); theArrowsCB.setEnabled(false); } }); final ButtonGroup group = new ButtonGroup(); group.add(owiBtn); group.add(oswBtn); group.add(rvlBtn); owiBtn.setSelected(true); theSelectedComp = "owi"; final JPanel componentTypePanel = new JPanel(new GridLayout(1, 4, 5, 5)); componentTypePanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); componentTypePanel.add(new JLabel("Component:")); componentTypePanel.add(owiBtn); componentTypePanel.add(oswBtn); componentTypePanel.add(rvlBtn); theControlLevel2Panel.add(componentTypePanel); final JPanel arrowDisplayPanel = new JPanel(new GridLayout(1, 2, 5, 5)); theArrowsCB = new JCheckBox(new AbstractAction() { public void actionPerformed(ActionEvent actionEvent) { // Simply enable or disable the layer based on its toggle button. if (((JCheckBox) actionEvent.getSource()).isSelected()) theOWIArrowsDisplayed = true; else theOWIArrowsDisplayed = false; wwd.redrawNow(); } }); arrowDisplayPanel.add(new JLabel("Display Wind Vectors:")); arrowDisplayPanel.add(theArrowsCB); theControlLevel2Panel.add(arrowDisplayPanel); /* final JPanel subsectionPanel = new JPanel(new GridLayout(1, 2, 5, 5)); JComboBox sectionDropDown = new JComboBox(); sectionDropDown.addItem("001"); sectionDropDown.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { SystemUtils.LOG.info("drop down changed"); } }); subsectionPanel.add(new JLabel("Subsection:")); subsectionPanel.add(sectionDropDown); theControlLevel2Panel.add(subsectionPanel); */ final JPanel maxPanel = new JPanel(new GridLayout(1, 2, 5, 5)); maxPanel.add(new JLabel("Max OWI Wind Speed:")); final JSpinner maxSP = new JSpinner(new SpinnerNumberModel(10, 0, 10, 1)); maxSP.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { int newValue = (Integer) ((JSpinner) e.getSource()).getValue(); theOWILimitChanged = true; } }); maxPanel.add(maxSP); theControlLevel2Panel.add(maxPanel); final JPanel minPanel = new JPanel(new GridLayout(1, 2, 5, 5)); minPanel.add(new JLabel("Min OWI Wind Speed:")); final JSpinner minSP = new JSpinner(new SpinnerNumberModel(0, 0, 10, 1)); minSP.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { theOWILimitChanged = true; } }); minPanel.add(minSP); theControlLevel2Panel.add(minPanel); final JPanel maxRVLPanel = new JPanel(new GridLayout(1, 2, 5, 5)); maxRVLPanel.add(new JLabel("Max RVL Rad Vel.:")); final JSpinner maxRVLSP = new JSpinner(new SpinnerNumberModel(6, 0, 10, 1)); maxRVLSP.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { int newValue = (Integer) ((JSpinner) e.getSource()).getValue(); theRVLLimitChanged = true; } }); maxRVLPanel.add(maxRVLSP); theControlLevel2Panel.add(maxRVLPanel); final JButton updateButton = new JButton("Update"); updateButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent actionEvent) { if (theOWILimitChanged) { //double minValue = ((Integer) minSP.getValue()) * 1.0e4; //double maxValue = ((Integer) maxSP.getValue()) * 1.0e4; double minValue = ((Integer) minSP.getValue()); double maxValue = ((Integer) maxSP.getValue()); recreateColorBarAndGradient(minValue, maxValue, "owi", wwd, theSelectedComp.equalsIgnoreCase("owi")); } if (theRVLLimitChanged) { //SystemUtils.LOG.info("theRVLLimitChanged"); //double minValue = ((Integer) minSP.getValue()) * 1.0e4; //double maxValue = ((Integer) maxSP.getValue()) * 1.0e4; double maxValue = ((Integer) maxRVLSP.getValue()); double minValue = -1 * maxValue; recreateColorBarAndGradient(minValue, maxValue, "rvl", wwd, theSelectedComp.equalsIgnoreCase("rvl")); } theOWILimitChanged = false; theRVLLimitChanged = false; } }); theControlLevel2Panel.add(updateButton); createColorBarLegend(0, 10, "OWI Wind Speed", "owi"); createColorBarLegend(0, 10, "OSW Wave Height.", "osw"); createColorBarLegend(-6, 6, "RVL Rad. Vel.", "rvl"); //addRenderable(theColorBarLegendHash.get("owi")); return theControlLevel2Panel; } }