// // WeatherSymbols.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad.meteorology; import visad.*; import visad.util.HersheyFont; import visad.java2d.DisplayImplJ2D; import javax.swing.JFrame; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; /** * Utility class to create shapes for weather symbols. Shapes are * stroke generated from the "wmo" HersheyFont. * @see "<a href="http://www.wmo.ch">WMO Manual on Codes</a> for a * description of WMO weather codes." */ public class WeatherSymbols { private static HersheyFont wmoFont = new HersheyFont("wmo"); private static final int numMetSymbols = 205; private static VisADLineArray[] metSymbols = new VisADLineArray[numMetSymbols]; /** starting index of present weather symbols in the whole list */ private final static int PRESENTWX_INDEX = 0; /** starting index of low cloud symbols in the whole list */ private final static int LOCLD_INDEX = 104; /** starting index of mid cloud symbols in the whole list */ private final static int MIDCLD_INDEX = 113; /** starting index of high cloud symbols in the whole list */ private final static int HICLD_INDEX = 122; /** starting index of pressure tendency symbols in the whole list */ private final static int TNDCY_INDEX = 142; /** starting index of cloud coverage symbols in the whole list */ private final static int SKY_INDEX = 131; /** starting index of icing symbols in the whole list */ private final static int TURB_INDEX = 151; /** starting index of icing symbols in the whole list */ private final static int ICING_INDEX = 160; /** starting index of misc symbols in the whole list */ private final static int MISC_INDEX = 171; /** Number of WMO weather symbols */ public final static int PRESENTWX_NUM = 104; /** Number of low cloud symbols */ public final static int LOCLD_NUM = 9; /** Number of mid cloud symbols */ public final static int MIDCLD_NUM = 9; /** Number of high cloud symbols */ public final static int HICLD_NUM = 9; /** Number of pressure tendency symbols */ public final static int TNDCY_NUM = 9; /** Number of cloud coverage symbols */ public final static int SKY_NUM = 11; /** Number of icing symbols */ public final static int ICING_NUM = 9; /** Number of turbulence symbols */ public final static int TURB_NUM = 11; /** Number of miscellaneous symbols */ public final static int MISC_NUM = 34; /** Number of lightning symbols */ public final static int LIGHTNING_NUM = 2; private static VisADLineArray[] lightningSymbols = new VisADLineArray[LIGHTNING_NUM]; static { // set up WMO symbols double[] start = { 0, -.5, 0 }; double[] base = { 1, 0, 0 }; double[] up = { 0, 1., 0 }; try { for (int i = 0; i < numMetSymbols; i++) { metSymbols[i] = PlotText.render_font( new String(new byte[] {(byte) (i+32)}, 0), wmoFont, start, base, up, true); } } catch (Exception excp) { System.err.println("Unable to intialize symbols properly"); } // set up lightning symbols VisADLineArray flash = new VisADLineArray(); flash.coordinates = new float[] { 0.25f, 0.8f, 0.0f, -0.25f, 0.0f, 0.0f, -0.25f, 0.0f, 0.0f, 0.25f, -0.8f, 0.0f, 0.0f, -0.8f, 0.0f, 0.25f, -0.8f, 0.0f, 0.25f,-0.8f, 0.0f, 0.25f, -0.55f, 0.0f}; flash.vertexCount = flash.coordinates.length / 3; lightningSymbols[0] = flash; flash = new VisADLineArray(); flash.coordinates = new float[] { -0.25f, 0.8f, 0.0f, 0.25f, 0.0f, 0.0f, 0.25f, 0.0f, 0.0f, -0.25f, -0.8f, 0.0f, 0.0f, -0.8f, 0.0f, -0.25f, -0.8f, 0.0f, -0.25f,-0.8f, 0.0f, -0.25f, -0.55f, 0.0f}; flash.vertexCount = flash.coordinates.length / 3; lightningSymbols[1] = flash; } /** * Default constructor. */ public WeatherSymbols() {} /** * Get the array of shapes corresponding to the * WMO present weather codes, plus the GEMPAK extensions. * @return the array of shapes */ public static VisADLineArray[] getPresentWeatherSymbols() { return subsetArray(metSymbols, PRESENTWX_INDEX, PRESENTWX_NUM); } /** * Get the array of shapes corresponding to the * WMO present weather codes, plus the GEMPAK extensions. * @return the array of shapes */ public static VisADLineArray[] getAllMetSymbols() { return subsetArray(metSymbols, 0, numMetSymbols); } /** * Get the shape corresponding to a particular present weather code. * The number of codes are too numerous to list here. * @param wxCode weather code * @return shape for code */ public static VisADLineArray getPresentWeatherSymbol(int wxCode) { if (wxCode < 0 || wxCode >= PRESENTWX_NUM) { throw new IllegalArgumentException( "unknown weather symbol: " + wxCode); } return getVLAClone(metSymbols, PRESENTWX_INDEX+wxCode); } /** * Get the array of shapes corresponding to the * pressure tendency symbol codes. * @return the array of shapes * @see #getPressureTendencySymbol for the indices */ public static VisADLineArray[] getPressureTendencySymbols() { return subsetArray(metSymbols, TNDCY_INDEX, TNDCY_NUM); } /** * Get the shape corresponding to a particular pressure * tendency code. Codes are: * <pre> * 0 - rising then falling * 1 - rising then steady; or rising, then rising more slowly * 2 - rising steadily or unsteadily * 3 - falling or steady, then rising; or rising, * then rising more quickly * 4 - steady, same as 3 hours ago * 5 - falling then rising, same or lower than 3 hours ago * 6 - falling then steady; or falling, then falling more slowly * 7 - falling steadily, or unsteadily * 8 - steady or rising, then falling; or falling, * then falling more quickly * </pre> * @param tendencyCode tendency code to use * @return corresponding shape */ public static VisADLineArray getPressureTendencySymbol(int tendencyCode) { if (tendencyCode < 0 || tendencyCode >= TNDCY_NUM) { throw new IllegalArgumentException( "unknown pressure tendency symbol: " + tendencyCode); } return getVLAClone(metSymbols, TNDCY_INDEX+tendencyCode); } /** * Get the array of shapes corresponding to the cloud coverage codes. * @return the array of shapes * @see #getCloudCoverageSymbol(int) for codes */ public static VisADLineArray[] getCloudCoverageSymbols() { return subsetArray(metSymbols, SKY_INDEX, SKY_NUM); } /** * Look up the symbol directly in the full array * * @param index array index * @return The symbol */ public static VisADLineArray getSymbol(int index) { if(index<0 || index>= metSymbols.length) { throw new IllegalArgumentException( "bad symbol index: " + index); } return getVLAClone(metSymbols,index); } /** * Get the shape corresponding to a total sky cover code. * Codes are: * <pre> * 0 - No clouds * 1 - Less than one-tenth or one-tenth * 2 - two-tenths or three-tenths * 3 - four-tenths * 4 - five-tenths * 5 - six-tenths * 6 - seven-tenths or eight-tenths * 7 - nine-tenths or overcast with openings * 8 - completely overcast * 9 - sky obscured * 10 - missing * </pre> * @param ccCode cloud coverage code to use * @return corresponding shape */ public static VisADLineArray getCloudCoverageSymbol(int ccCode) { if (ccCode < 0 || ccCode >= SKY_NUM) { throw new IllegalArgumentException( "unknown cloud coverage symbol: " + ccCode); } return getVLAClone(metSymbols, SKY_INDEX+ccCode); } /** * Get the array of shapes corresponding to the low cloud codes. * @return the array of shapes * @see #getLowCloudSymbol(int) for codes */ public static VisADLineArray[] getLowCloudSymbols() { return subsetArray(metSymbols, LOCLD_INDEX, LOCLD_NUM); } /** * Get the shape corresponding to a particular low cloud code. * Codes are: * <pre> * 1 - Cu of fair weather, little vertical development, * seemingly flattened * 2 - Cu of considerable development, generally towering, * with or without other Cu or Sc bases all at same level * 3 - Cb with tops lacking clear cut outlines, but distinctly * no cirriform or anvil-shaped; with or without Cu, Sc, or St * 4 - Sc formed by spreading out of Cu; Cu often present also * 5 - Sc not formed by spreading out of Cu * 6 - St or Fs or both, but no Fs of bad weather * 7 - Fs and/or Fc of bad weather (scud) * 8 - Cu and Sc (not formed by spreading out of Cu) with bases * at different levels * 9 - Cb having a clearly fibrous (cirriform) top, often anvil-shaped, * with or without Cu, Sc, St, or scud * </pre> * @param lcCode low cloud code to use * @return corresponding shape */ public static VisADLineArray getLowCloudSymbol(int lcCode) { if (lcCode < 1 || lcCode > LOCLD_NUM) { throw new IllegalArgumentException( "unknown low cloud symbol: " + lcCode); } return getVLAClone(metSymbols, LOCLD_INDEX+lcCode-1); } /** * Get the array of shapes corresponding to the mid cloud codes. * @return the array of shapes * @see #getMidCloudSymbol(int) for codes */ public static VisADLineArray[] getMidCloudSymbols() { return subsetArray(metSymbols, MIDCLD_INDEX, MIDCLD_NUM); } /** * Get the shape corresponding to a particular mid level cloud code. * Codes are: * <pre> * 1 - Thin As (most of cloud layer semi-transparent) * 2 - Thick As, greater part sufficiently dense to hide sun * (or moon), or Ns * 3 - Thin Ac, mostly semi-transparent; cloud elements not changing * much and at a single level * 4 - Thin Ac in patches; cloud elements continually changing and/or * occurring at more than one level * 5 - Thin Ac in bands or in a layer gradually spreading over sky * and usually thickening as a whole * 6 - Ac formed by spreading out of Cu * 7 - Double-layered Ac, or a thick layer of Ac, not increasing; * or Ac with As and/or Ns * 8 - Ac in the form of Cu-shaped tufts or Ac with turrets * 9 - Ac of a chaotic sky, usually at different levels; patches of * dense Ci are usually present also * </pre> * @param mcCode mid cloud code to use * @return corresponding shape */ public static VisADLineArray getMidCloudSymbol(int mcCode) { if (mcCode < 1 || mcCode > MIDCLD_NUM) { throw new IllegalArgumentException( "unknown mid cloud symbol: " + mcCode ); } return getVLAClone(metSymbols, MIDCLD_INDEX+mcCode-1); } /** * Get the array of shapes corresponding to the high cloud codes. * @return the array of shapes * @see #getHighCloudSymbol(int) for codes */ public static VisADLineArray[] getHighCloudSymbols() { return subsetArray(metSymbols, HICLD_INDEX, HICLD_NUM); } /** * Get the shape corresponding to a particular high cloud code. * Codes are: * <pre> * 1 - Filaments of Ci, or "mares tails", scattered and not increasing * 2 - Dense Ci in patches or twisted sheaves, usually not increasing, * sometimes like remains of Cb; or towers or tufts * 3 - Dense Ci, often anvil shaped derived from or associated with Cb * 4 - Ci, often hook shaped, spreading over the sky and usually * thickening as a whole * 5 - Ci and Cs, often in converging bands, or Cs alone; generally * overspreading and growing denser; the continuous layer * not reaching 45 degrees altitude * 6 - Ci and Cs, often in converging bands, or Cs alone; generally * overspreading and growing denser; the continuous layer * exceeding 45 degrees altitude * 7 - Veil of Cs covering the entire sky * 8 - Cs not increasing and not covering the entire sky * 9 - Cc alone or Cc with some Ci or Cs, but the Cc being the main * cirriform cloud * </pre> * @param hcCode high cloud code to use * @return corresponding shape */ public static VisADLineArray getHighCloudSymbol(int hcCode) { if (hcCode < 1 || hcCode > HICLD_NUM) { throw new IllegalArgumentException( "unknown high cloud symbol: " + hcCode ); } return getVLAClone(metSymbols, HICLD_INDEX+hcCode-1); } /** * Get the array of shapes corresponding to the icing codes. * @return the array of shapes * @see #getIcingSymbol(int) for codes */ public static VisADLineArray[] getIcingSymbols() { return subsetArray(metSymbols, ICING_INDEX, ICING_NUM); } /** * Get the shape corresponding to a particular icing symbol code. * Codes are: * <pre> * 0 - No icing * 1 - Trace icing * 2 - Trace to light icing * 3 - Light icing * 4 - Light to moderate icing * 5 - Moderate icing * 6 - Moderate to heavy icing * 7 - Heavy or moderate to severe icing * 8 - Severe icing * 9 - Light superstructure icing * 10 - Heavy superstructure icing * </pre> * @param icingCode icing code to use * @return corresponding shape */ public static VisADLineArray getIcingSymbol(int icingCode) { if (icingCode < 0 || icingCode >= ICING_NUM) { throw new IllegalArgumentException( "unknown icing symbol: " + icingCode ); } return getVLAClone(metSymbols, ICING_INDEX+icingCode); } /** * Get the array of shapes corresponding to the turbulence codes. * @return the array of shapes * @see #getTurbulenceSymbol(int) for codes */ public static VisADLineArray[] getTurbulenceSymbols() { return subsetArray(metSymbols, TURB_INDEX, TURB_NUM); } /** * Get the shape corresponding to a particular turbulence symbol code. * Codes are: * <pre> * 0 - No turbulence * 1 - Light turbulence * 2 - Light turbulence * 3 - Light to moderate turbulence * 4 - Moderate turbulence * 5 - Moderate to severe turbulence * 6 - Severe turbulence * 7 - Extreme turbulence * 8 - Extreme turbulence * </pre> * @param turbCode turbulence code to use * @return corresponding shape */ public static VisADLineArray getTurbulenceSymbol(int turbCode) { if (turbCode < 0 || turbCode >= TURB_NUM) { throw new IllegalArgumentException( "unknown turbulence symbol: " + turbCode ); } return getVLAClone(metSymbols, TURB_INDEX+turbCode); } /** * Get the array of shapes corresponding to the miscellaneous codes. * @return the array of shapes * @see #getMiscSymbol(int) for codes */ public static VisADLineArray[] getMiscSymbols() { return subsetArray(metSymbols, MISC_INDEX, MISC_NUM); } /** * Get the shape corresponding to a particular miscellaneous symbol. * Codes are: * <pre> * 0 - Square (outline) 16 - Tropical Storm (NH) * 1 - Square (filled) 17 - Hurricane (NH) * 2 - Circle (outline) 18 - Tropical Storm (SH) * 3 - Circle (filled) 19 - Hurricane (SH) * 4 - Triangle (outline) 20 - Triangle with antenna * 5 - Triangle (filled) 21 - Mountain obscuration * 6 - Diamond (outline) 22 - Slash * 7 - Diamond (filled) 23 - Storm Center * 8 - Star (outline) 24 - Tropical Depression * 9 - Star (filled) 25 - Tropical Cyclone * 10 - High Pressure (outline) 26 - Flame * 11 - Low Pressure (outline) 27 - "X" Cross * 12 - High Pressure (filled) 28 - Low pressure with X (outline) * 13 - Low Pressure (filled) 29 - Low pressure with X (filled) * 14 - Plus sign 30 - Tropical Storm (NH) * 15 - Minus sign 31 - Tropical Storm (SH) * 32 - Volcanic activity 33 - Blowing spray * </pre> * @param miscCode miscellaneous code to use * @return corresponding shape */ public static VisADLineArray getMiscSymbol(int miscCode) { if (miscCode < 0 || miscCode >= MISC_NUM) { throw new IllegalArgumentException( "unknown turbulence symbol: " + miscCode ); } return getVLAClone(metSymbols, MISC_INDEX+miscCode); } /** * Get the array of shapes corresponding to lightning symbols * @return the array of shapes * @see #getLightningSymbol(int) for codes */ public static VisADLineArray[] getLightningSymbols() { return subsetArray(lightningSymbols, 0, LIGHTNING_NUM); } /** * Get the shape corresponding to a particular lightning code. * Codes are: * <pre> * 0 - Negative flash * 1 - Positive flash * </pre> * @param lghtCode lightning code to use * @return corresponding shape */ public static VisADLineArray getLightningSymbol(int lghtCode) { if (lghtCode < 0 || lghtCode >= LIGHTNING_NUM) { throw new IllegalArgumentException( "unknown lightning symbol: " + lghtCode ); } return getVLAClone(lightningSymbols, lghtCode); } private static VisADLineArray[] subsetArray(VisADLineArray[] array, int start, int number) { VisADLineArray[] retArray = new VisADLineArray[number]; for (int i = 0; i < number; i++) { retArray[i] = (VisADLineArray) array[start+i].clone(); } return retArray; } private static VisADLineArray getVLAClone(VisADLineArray[] array, int index) { return (VisADLineArray) array[index].clone(); } public static void main( String[] args) throws Exception { DisplayImpl display = new DisplayImplJ2D("display"); display.getDisplayRenderer().setBoxOn(false); double[] matrix = display.getProjectionControl().getMatrix(); matrix[0] = 1.25; matrix[3] = -1.25; display.getProjectionControl().setMatrix(matrix); display.addMap(new ScalarMap(RealType.YAxis, Display.YAxis)); display.addMap(new ScalarMap(RealType.XAxis, Display.XAxis)); float[][] values = new float[3][220]; int l = 0; for (int x = 0; x < 11; x++) { for (int y = 0; y < 20; y++) { values[0][l] = -1.f + y/10.f; values[1][l] = 1.f - x/4.f; values[2][l] = l++; } } Gridded3DSet set = new Gridded3DSet(RealTupleType.SpatialCartesian3DTuple, values, l); ScalarMap shapeMap = new ScalarMap(RealType.ZAxis, Display.Shape); display.addMap(shapeMap); ShapeControl sc = (ShapeControl) shapeMap.getControl(); sc.setShapeSet(new Integer1DSet(l)); sc.setShapes(WeatherSymbols.getAllMetSymbols()); sc.setScale(0.1f); DataReference ref = new DataReferenceImpl("ref"); ref.setData(set); display.addReference(ref); JFrame frame = new JFrame("Weather Symbol Plot Test"); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.getContentPane().add(display.getComponent()); frame.pack(); frame.setSize(500, 500); frame.setVisible(true); } }