//
//  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 "WMO Manual on Codes 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:
   * 
   *   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
   * 
* @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: *
   *   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
   * 
* @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: *
   *   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
   * 
* @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: *
   *   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
   * 
* @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: *
   *   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
   * 
* @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: *
   *   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
   * 
* @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: *
   *   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
   * 
* @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: *
   *   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
   * 
* @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: *
   *   0  -  Negative flash
   *   1  -  Positive flash
   * 
* @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); } }

Ads help maintain this website.