JEphem Informatic Trail build classes source code BuildConstellations.java
//*********************************************************************************
// class BuildConstellations // default package
// Software released under the General Public License (version 2 or later), available at
// http://www.gnu.org/copyleft/gpl.html
//*********************************************************************************
import java.io.*;
import java.util.*;

import tig.Strings;
import tig.Formats;

/******************************************************************
Parsing and building constellation classes of package <CODE>jephem.astro.sky</CODE>.

@author Thierry Graff
@history apr 30 2002 : Creation
@history may 02 2002 : BuildRomanData
@todo
*****************************************************************/
public abstract class BuildConstellations{

  //=================================================================================
  //                            CONSTANTS
  //=================================================================================

  // parameters for 1st argument of main()
  private static final String PARAM_BUILD_NAMES = "buildNames";
  private static final String PARAM_BUILD_ABBREVIATIONS = "buildAbbreviations";
  private static final String PARAM_BUILD_BOUNDARIES = "buildBoundaries";
  private static final String PARAM_BUILD_ROMAN = "buildRomanData";


  private final static String LS = System.getProperty("line.separator");
  private final static String PLUS = "+";
  private final static String MINUS = "-";
  private final static String COMA = ",";
  private final static String POINT = ".";
  private final static String BLANK = "";
  private final static String SPACE = " ";


  //=================================================================================
  //                                      PUBLIC METHODS
  //=================================================================================

  //**************** main ************************
  /** Entry point to use this class.
  @param args The first parameter indicates which method will be called.
  <BR>if equals to "buildNames" or "buildAbbreviations", buildNames() is called.
  <BR>if equals to "buildBoundaries", buildBoundaries() is called.
  <BR>The following arguments are passed to the called method.
  */
  public static void main(String[] args){

    // Parameter checking
    String paramList = "'" + PARAM_BUILD_NAMES + "' or '" + PARAM_BUILD_ABBREVIATIONS + "' or '" +
                       PARAM_BUILD_BOUNDARIES + "' or '" + PARAM_BUILD_ROMAN + "'";
    if (args.length == 0){
      System.out.println("Call to main must have at least one parameter :");
      System.out.println(paramList);
      System.exit(0);
    }

    if (args[0].compareToIgnoreCase(PARAM_BUILD_NAMES) == 0 ||
        args[0].compareToIgnoreCase(PARAM_BUILD_ABBREVIATIONS) == 0){
        if(args.length != 3){
          System.out.println("Call to buildNames must be done with 2 arguments :");
          System.out.println("input file format, output file name");
          System.exit(0);
        }
        buildNames(args[0], args[1], args[2]);
    }
    else if (args[0].compareToIgnoreCase(PARAM_BUILD_BOUNDARIES) == 0){
        if(args.length != 3){
          System.out.println("Call to buildBoundaries must be done with 2 arguments :");
          System.out.println("input file format, output file name");
          System.exit(0);
        }
        buildBoundaries(args[1], args[2]);
    }
    else if (args[0].compareToIgnoreCase(PARAM_BUILD_ROMAN) == 0){
        if(args.length != 3){
          System.out.println("Call to buildRomanData must be done with 2 arguments :");
          System.out.println("input file format, output file name");
          System.exit(0);
        }
        buildRomanData(args[1], args[2]);
    }

    else{
      System.out.println("First parameter must be :");
      System.out.println(paramList);
    }

  }// end main

  //**************** buildNames() ************************
  /** Used to generate name array for class <CODE>jephem.astro.sky.Constellations</CODE> or
  abbreviation constants for interface <CODE>jephem.astro.sky.Constellations</CODE>.
  <BR>Original file coming from <A HREF="find the address.com">find the address.com</A>,
  manually reformatted.
  */
  public static void buildNames(String outputType, String inputFileName, String outputFileName){

    int i = 0;
    try{
      LineNumberReader lnr = new LineNumberReader(new FileReader(new File(inputFileName)));

      int NB_LINES = 88; // nb of input lines
      String[] tmpArray = new String[3];
      String[] res = new String[NB_LINES];
      String line;
      int tmp;

      // *** 1 - Fill the intermediate array.
      for(i = 0; i < NB_LINES; i++){
        // get nominative
        line = lnr.readLine();
        tmpArray[1] = line.trim();
        // get abbreviation
        line = lnr.readLine();
        tmpArray[0] = line.trim();
        // get abbreviation
        line = lnr.readLine();
        tmpArray[2] = line.trim();
        res[i] = tmpArray[0] + COMA + tmpArray[1] + COMA + tmpArray[2];
        //System.out.println(res[i][0] + " - " + res[i][1] + " - " + res[i][2]);
      }
      lnr.close();

      // *** 2 - Sort the intermediate array.
      java.util.Arrays.sort(res);
      for(i = 0; i < NB_LINES; i++)
        System.out.println(res[i]);

      // *** 3 - Generate the output
      FileOutputStream fos = new FileOutputStream(new File(outputFileName));
      StringBuffer buffer = new StringBuffer();

      // Write headers
      if(outputType.compareToIgnoreCase(PARAM_BUILD_NAMES) == 0){
        buffer.append("  /** Contains the abbreviation, nominative and genitive of constellations. */").append(LS);
        buffer.append("  private static final String[][] _names = {").append(LS);
      }

      // Loop
      for(i = 0; i < NB_LINES; i++){
        tmpArray = Strings.stringToStringArray(res[i]);
        if(outputType.compareToIgnoreCase(PARAM_BUILD_ABBREVIATIONS) == 0){
          buffer.append("  /** Constant to access to \"");
          buffer.append(tmpArray[1]).append("\" constellation. */").append(LS);
          buffer.append("  public static final int ").append(tmpArray[0]);
          buffer.append(" = ").append(i).append(";").append(LS).append(LS);
        }
        if(outputType.compareToIgnoreCase(PARAM_BUILD_NAMES) == 0){
          buffer.append("    {\"").append(tmpArray[0]).append("\", \"");
          buffer.append(tmpArray[1]).append("\", \"");
          buffer.append(tmpArray[2]).append("\"}");
          if(i < NB_LINES - 1) buffer.append(",");
          buffer.append(LS);
        }
      }// end for

      // Write Footers
      if(outputType.compareToIgnoreCase(PARAM_BUILD_NAMES) == 0)
          buffer.append("  }; // end _names").append(LS);

      fos.write(buffer.toString().getBytes());
      fos.close();
    }
    catch(Exception e){
      System.out.println("stuck at line " + i);
      e.printStackTrace();
    }
  }// end buildNames()


  //**************** buildBoundaries() ************************
  /** Used to generate boundary array for class <CODE>jephem.astro.sky.Constellations</CODE> .
  <BR>Original file coming from <A HREF="find the address.com">find the address.com</A>,
  manually reformatted.
  <BR>Serpens must be done manually.
  */
  public static void buildBoundaries(String inputFileName, String outputFileName){
    int i = 0, j = 0;
    try{
      LineNumberReader lnr;

      String line;
      int tmp;

      final String MARKER = " I         "; // always present at beginning of a constellation.

      // *** 1 - First pass, to count the constellations.
      lnr = new LineNumberReader(new FileReader(new File(inputFileName)));
      while((line = lnr.readLine()) != null){
        tmp = line.indexOf(MARKER);
        if(tmp != -1){
          //System.out.println(line.substring(tmp + 1));
          i++;
        }
      }
      final int NB_CONST = i; // = 89 (the 88 + Serpens pb)
      System.out.println("========== nb const : " + i);
      lnr.close();
      lnr = null;


      // *** 2 - Second pass, to count the nb of elements in each const.
      lnr = new LineNumberReader(new FileReader(new File(inputFileName)));
      int[] nbElements = new int[NB_CONST]; // nb of pairs (ra, dec in a given const)
      int curConst = 0; // index of the current const.
      int curNb = 0; // nb of elements in current constellation
      while((line = lnr.readLine()) != null){
        i++; // identify the line nb (just for error msg).
        tmp = line.indexOf(MARKER);
        if(tmp != -1){
          if(curConst != 0){
            nbElements[curConst - 1] = curNb;
          }
          curConst ++;
          curNb = 0;
          //System.out.println(line.substring(tmp + 1));
        }
        else{
          curNb++;
        }
      }// end while
      nbElements[NB_CONST - 1] = curNb;
      lnr.close();
      lnr = null;

      // trace
//      for(i = 0; i < NB_CONST; i++){
//        System.out.println("const " + i + " : " + elements[i]);
//      }

      // *** 3 - Third pass, to fill the arrays.
      // two arrays : one containing the names, an other one containing the Strings with the coords
      String[] names = new String[NB_CONST];
      String[][] coords = new String[NB_CONST][];
      lnr = new LineNumberReader(new FileReader(new File(inputFileName)));
      // skip header lines
      for(i = 0; i < 5; i++){
        line = lnr.readLine();
      }

      curConst = 0;
      curNb = 0;
      i = 0;
      while((line = lnr.readLine()) != null){
        i++; // identify the line nb (just for error msg).
        tmp = line.indexOf(MARKER);
        if(tmp != -1){
          names[curConst] = line.substring(tmp+2).trim(); // retrieve the name
          coords[curConst] = new String[nbElements[curConst]]; // allocate
          curConst ++;
          curNb = 0;
        }
        else{
          //System.out.println("---- " + line + " curConst = " + curConst + " curNb = " + curNb);
          coords[curConst - 1][curNb] = line.substring(0, line.indexOf("V")).trim();
          curNb++;
        }
      }// end while
      lnr.close();

      // trace
      for(i = 0; i < NB_CONST; i++){
        System.out.println(" ==== const " + i + " : " + names[i]);
//        for(j = 0; j < nbElements[i]; j++){
//          System.out.println("  " + coords[i][j]);
//        }
      }

      // *** 4 - Build the output from the arrays.
      final int OFFICIAL_NB = 88; // the nb of const in the other arrays of class Constellations
      FileOutputStream fos = new FileOutputStream(new File(outputFileName));
      StringBuffer strRes = new StringBuffer();
      int k;
      strRes.append("  /** Boundaries of the constellations.").append(LS);
      strRes.append("  <BR>Values in radians, for mean equator and equinox 1875.0.").append(LS);
      strRes.append("  <BR>WARNING : _boundaries[Ser] contains data for serpens caput.").append(LS);
      strRes.append("  Data for serpens cauda are at _boundaries[NB_CONSTELLATIONS].").append(LS);
      strRes.append("  */").append(LS);
      strRes.append("  private final static double[][][] _boundaries = {").append(LS);
      // method : scan the "official" array (_names), find the corresponding element of
      // temp arrays (names and coords). The output is then ordered correctly ; serpens cauda is put at the end
      for(i = 0; i < OFFICIAL_NB; i++){
        for(j = 0; j < NB_CONST; j++){
          if(_names[i][1].equalsIgnoreCase(names[j]) ||
             _names[i][1].equals("Serpens") && names[j].equals("SERPENS CAPUT")){
            strRes.append("    { // data for ");
            if(_names[i][1].equals("Serpens")) strRes.append("Serpens Caput").append(LS);
            else strRes.append(_names[i][1]).append(LS);
            for(k = 0; k < nbElements[j]; k++){
              strRes.append("      {");
              strRes.append(getRa(coords[j][k].substring(0, 8)));
              strRes.append(", ");
              strRes.append(getDec(coords[j][k].substring(9)));
              if(k == nbElements[j] - 1) strRes.append("}").append(LS);
              else strRes.append("},").append(LS);
            }// end for k
            strRes.append("    },").append(LS);
          }// end if
        }// end for j
      }// end for i

      // add data for serpens cauda ...
      strRes.append("    { // data for Serpens Cauda").append(LS);
      final int serCaudaIdx = 48; // (found in trace of step 3)
      for(k = 0; k < nbElements[serCaudaIdx]; k++){
        strRes.append("      {");
        strRes.append(getRa(coords[serCaudaIdx][k].substring(0, 8)));
        strRes.append(", ");
        strRes.append(getDec(coords[serCaudaIdx][k].substring(9)));
        if(k == nbElements[serCaudaIdx] - 1) strRes.append("}").append(LS);
        else strRes.append("},").append(LS);
      }// end for k
      strRes.append("    }").append(LS);

      // ... and finish
      strRes.append("  }; // end _boundaries").append(LS);
      fos.write(strRes.toString().getBytes());
      fos.close();
    }
    catch(Exception e){
      System.out.println("stuck at line " + i);
      e.printStackTrace();
    }
  } // end buildBoundaries

  //**************** buildRomanData() ************************
  /** Used to generate arrays for class <CODE>jephem.astro.sky.Constellations</CODE> ; these arrays
  contain data to find a constellation from a position (cf N. G. Roman work).
  */
  public static void buildRomanData(String inputFileName, String outputFileName){
    int i = 0;
    try{
      LineNumberReader lnr = new LineNumberReader(new FileReader(new File(inputFileName)));

      int NB_LINES = 357; // nb of input lines
      String line;
      StringBuffer strRes1 = new StringBuffer();
      StringBuffer strRes2 = new StringBuffer();
      String strTmp;

      // 1 - write headers
      strRes1.append("  /** Contains the numeric data used to compute a constellation from a position.").append(LS);
      strRes1.append("  <BR>_romanDoubles[i][] contains the data named \"RAl\", \"RAu\", \"Decl\" ");
      strRes1.append("in the original work.").append(LS);
      strRes1.append("  <BR>All the values are stored in radians, and related to the 1875.0 equator and equinox.").append(LS);
      strRes1.append("  <BR>This array is used with _romanStrings. */").append(LS);
      strRes1.append("  private static final double[][] _romanDoubles = {").append(LS);

      strRes2.append("  /** Contains the String data used to compute a constellation from a position.").append(LS);
      strRes2.append("  <BR>_romanStrings[i] contains the data named \"Con\" in the original work.").append(LS);
      strRes2.append("  <BR>This array is used with _romanDoubles. */").append(LS);
      strRes2.append("  private static final String[] _romanStrings = {").append(LS);

      // 2 - parse the file
      for(i = 0; i < NB_LINES; i++){
      //for(i = 0; i < 10; i++){
        line = lnr.readLine();
        strRes1.append("    {");

        // compute RAl
        strTmp = reformatRA(line.substring(0, 8).trim());
        strRes1.append(getRa(strTmp)).append(", ");
        // compute RAu
        strTmp = reformatRA(line.substring(9, 16).trim());
        strRes1.append(getRa(strTmp)).append(", ");
        // compute Decl
        strTmp = reformatDec(line.substring(17, 26).trim());
        strRes1.append(getDec2(strTmp)).append("}");
        // compute Con
        strRes2.append("    \"").append(line.substring(26).trim()).append("\"");
        //System.out.println((i+1) + " : " + strTmp);
        
        if(i < NB_LINES - 1){
          strRes1.append(COMA);
          strRes2.append(COMA);
        }
        strRes1.append(LS);
        strRes2.append(LS);
      }
      lnr.close();

      // 3 - Write footers
      strRes1.append("  }; // end _romanDoubles" + LS);
      strRes2.append("  }; // end _romanStrings" + LS);


      FileOutputStream fos = new FileOutputStream(new File(outputFileName));
      fos.write(strRes1.toString().getBytes());
      fos.write(LS.getBytes());
      fos.write(strRes2.toString().getBytes());
      fos.close();
    }
    catch(Exception e){
      System.out.println("stuck at line " + i);
      e.printStackTrace();
    }
  }// end buildRomanData()

  //=================================================================================
  //                              AUXILIARY METHODS FOR buildBoundaries
  //=================================================================================
  //*************************************************
  /** Auxiliary method which converts ra from input file to <B>radians</B>.
  @param str Contains the ra as formatted in the input file : HH MM SS
  */
  // adapted from BuildBSC5 to the format of ConstBoundary.dat
  private static double getRa(String str){
    try{
      double hours = Double.parseDouble(str.substring(0,2));
//			System.out.println("ra - parsed hours : " + hours);
      double minuts = Double.parseDouble(str.substring(3,5))/60.0; // convert minuts to decimal hours
//			System.out.println("ra - parsed minuts : " + minuts);
      double seconds = Double.parseDouble(str.substring(5))/3600.0; // convert seconds to decimal hours
//			System.out.println("ra - parsed seconds : " + seconds);
      double res = hours + minuts + seconds;
      res *= 15.0; // convert to degrees
      return Math.toRadians(res);
    }catch (NumberFormatException nfe){
      System.out.println("getRa - Unable to parse '" + str + "'");
      return 0.0;
    }
  }// end getRa

  //*************************************************
  /** Auxiliary method which converts dec from input file format to <B>radians</B>.
  @param str Contains the dec as formatted in the input file : sDDMM (s = sign).
  */
  // adapted from BuildBSC5 to the format of ConstBoundary.dat
  // also used by buildRomanData()
  private static double getDec(String str){
    try{
      double deg = Double.parseDouble(str.substring(0,3));
//			System.out.println("dec - parsed deg : " + deg);
      double minuts = Double.parseDouble(str.substring(4))/60.0; // convert minuts to decimal degrees
//			System.out.println("dec - parsed minuts " + minuts);
      double res = deg + minuts;
      return Math.toRadians(res);
    }catch (NumberFormatException nfe){
      System.out.println("getDec - Unable to parse '" + str + "'");
      return 0.0;
    }
  }// end getDec

  //=================================================================================
  //                              AUXILIARY METHODS FOR buildRomanData
  //=================================================================================

  //**************** reformatRA() ************************
  /** Auxiliary method of buildRomanData.*/
  private static String reformatRA(String ra){
    int tmp = ra.indexOf(POINT);
    int nbHours = Integer.parseInt(ra.substring(0, tmp));
    int decPart = Integer.parseInt(ra.substring(tmp + 1));
    double dblSec = 0.36*decPart; // 0.36 = 3600 / 10E4 ; dblSec = exact nb of hour sec in ra
    int nbMin = (int)Math.floor(dblSec/60);
    int nbSec = (int)Math.round(dblSec - (double)nbMin*60);
    if(nbSec == 60){
      nbSec = 0;
      nbMin ++;
      if(nbMin==60){
        nbMin = 0;
        nbHours ++;
      }
    }
    boolean traceCheck = false;
    // first check : dec. part of dblSec
    double dblSecDecPart = dblSec - Math.floor(dblSec);
    if(traceCheck && dblSecDecPart != 0) System.out.println("dblSecDecPart = " + dblSecDecPart);
    // second check : difference between Roman file value and reformated value
    if(traceCheck){
      double ra1 = Double.parseDouble(ra);
      double ra2 = (double)nbHours + (double)nbMin/60 + (double)nbSec/3600;
      if(ra2 - ra1 != 0)
        System.out.println("ra1 : " + ra1 + "  ra2 : " + ra2 + "   ra2 - ra1 : " + (ra2 - ra1));
    }
    return Formats.addZero(nbHours) + SPACE + Formats.addZero(nbMin) + SPACE + Formats.addZero(nbSec);
  }// end reformatRA
  
  //**************** reformatDec() ************************
  /** Auxiliary method of buildRomanData.*/
  private static String reformatDec(String dec){
    int tmp = dec.indexOf(POINT);
    int nbDeg = Integer.parseInt(dec.substring(0, tmp));
    int decPart = Integer.parseInt(dec.substring(tmp + 1));
    double dblSec= 0.36*decPart; // 0.36 = 3600 / 10E4 - dblSec = exact nb of arc sec in dec
    int nbMin = (int)Math.floor(dblSec/60);
    int nbSec = (int)Math.round(dblSec - (double)nbMin*60);
    if(nbSec == 60){
      nbSec = 0;
      nbMin ++;
      if(nbMin==60){
        nbMin = 0;
        nbDeg ++;
      }
    }
    boolean traceCheck = false;
    // first check : dec. part of dblSec
    double dblSecDecPart = dblSec - Math.floor(dblSec);
    if(traceCheck && dblSecDecPart != 0) System.out.println("dblSecDecPart = " + dblSecDecPart);
    // second check : difference between Roman file value and reformated value
    if(traceCheck){
      double dec1 = Double.parseDouble(dec);
      double dec2 = (double)nbDeg + (nbDeg > 0 ? (double)nbMin/60 + (double)nbSec/3600 : -(double)nbMin/60 - (double)nbSec/3600);
      if(dec2 - dec1 != 0)
        System.out.println("dec1 : " + dec1 + "   dec2 : " + dec2 + "   dec2 - dec1 : " + (dec2 - dec1) + LS);
    }
    String strRes = BLANK;
    if(nbDeg > 0) strRes += PLUS + Formats.addZero(nbDeg);
    else if(nbDeg == 0) strRes += " 00";
    else strRes += MINUS + Formats.addZero(-nbDeg);
    return strRes + SPACE + Formats.addZero(nbMin) + SPACE + Formats.addZero(nbSec);
  }// end reformatDec
  
  //*************************************************
  /** Auxiliary method which converts dec from input file format to <B>radians</B>.
  @param str Contains the dec as formatted in the input file : sDDMM (s = sign).
  */
  // adapted from BuildBSC5 for buildRomanData
  private static double getDec2(String str){
    try{
      double deg = Double.parseDouble(str.substring(0,3));
      double minuts = Double.parseDouble(str.substring(4, 6))/60.0;
      double seconds = Double.parseDouble(str.substring(7))/3600.0;
			//System.out.println("getDec2 - str = " + str + "  deg = " + deg + "  min = " + minuts + "  sec : " + seconds);
      double res = deg + minuts + seconds;
      return Math.toRadians(res);
    }catch (NumberFormatException nfe){
      System.out.println("getDec - Unable to parse '" + str + "'");
      throw nfe;
    }
  }// end getDec2

  //=================================================================================
  //                   COPIED FROM CLASS jephem.astro.sky.Constellations
  //                   (array generated by buildNames())
  //=================================================================================
  /** Contains the abbreviation, nominative and genitive of constellations. */
  private static final String[][] _names = {
    {"And", "Andromeda", "Andromedae"},
    {"Ant", "Antlia", "Antliae"},
    {"Aps", "Apus", "Apodis"},
    {"Aql", "Aquila", "Aquilae"},
    {"Aqr", "Aquarius", "Aquarii"},
    {"Ara", "Ara", "Arae"},
    {"Ari", "Aries", "Arietis"},
    {"Aur", "Auriga", "Aurigae"},
    {"Boo", "Bootes", "Bootis"},
    {"CMa", "Canis Major", "Canis Majoris"},
    {"CMi", "Canis Minor", "Canis Minoris"},
    {"CVn", "Canes Venatici", "Canum Venaticorum"},
    {"Cae", "Caelum", "Caeli"},
    {"Cam", "Camelopardalis", "Camelopardalis"},
    {"Cap", "Capricornus", "Capricorni"},
    {"Car", "Carina", "Carinae"},
    {"Cas", "Cassiopeia", "Cassiopeiae"},
    {"Cen", "Centaurus", "Centauri"},
    {"Cep", "Cepheus", "Cephei"},
    {"Cet", "Cetus", "Ceti"},
    {"Cha", "Chamaeleon", "Chamaeleontis"},
    {"Cir", "Circinus", "Circini"},
    {"Cnc", "Cancer", "Cancri"},
    {"Col", "Columba", "Columbae"},
    {"Com", "Coma Berenices", "Comae Berenices"},
    {"CrA", "Corona Austrina", "Coronae Austrinae"},
    {"CrB", "Corona Borealis", "Coronae Borealis"},
    {"Crt", "Crater", "Crateris"},
    {"Cru", "Crux", "Crucis"},
    {"Crv", "Corvus", "Corvi"},
    {"Cyg", "Cygnus", "Cygni"},
    {"Del", "Delphinus", "Delphini"},
    {"Dor", "Dorado", "Doradus"},
    {"Dra", "Draco", "Draconis"},
    {"Equ", "Equuleus", "Equulei"},
    {"Eri", "Eridanus", "Eridani"},
    {"For", "Fornax", "Fornacis"},
    {"Gem", "Gemini", "Geminorum"},
    {"Gru", "Grus", "Gruis"},
    {"Her", "Hercules", "Herculis"},
    {"Hor", "Horologium", "Horologii"},
    {"Hya", "Hydra", "Hydrae"},
    {"Hyi", "Hydrus", "Hydri"},
    {"Ind", "Indus", "Indi"},
    {"LMi", "Leo Minor", "Leonis Minoris"},
    {"Lac", "Lacerta", "Lacertae"},
    {"Leo", "Leo", "Leonis"},
    {"Lep", "Lepus", "Leporis"},
    {"Lib", "Libra", "Librae"},
    {"Lup", "Lupus", "Lupi"},
    {"Lyn", "Lynx", "Lyncis"},
    {"Lyr", "Lyra", "Lyrae"},
    {"Men", "Mensa", "Mensae"},
    {"Mic", "Microscopium", "Microscopii"},
    {"Mon", "Monoceros", "Monocerotis"},
    {"Mus", "Musca", "Muscae"},
    {"Nor", "Norma", "Normae"},
    {"Oct", "Octans", "Octantis"},
    {"Oph", "Ophiuchus", "Ophiuchi"},
    {"Ori", "Orion", "Orionis"},
    {"Pav", "Pavo", "Pavonis"},
    {"Peg", "Pegasus", "Pegasi"},
    {"Per", "Perseus", "Persei"},
    {"Phe", "Phoenix", "Phoenicis"},
    {"Pic", "Pictor", "Pictoris"},
    {"PsA", "Piscis Austrinus", "Piscis Austrini"},
    {"Pse", "Pisces", "Piscium"},
    {"Pup", "Puppis", "Puppis"},
    {"Pyx", "Pyxis", "Pyxidis"},
    {"Ret", "Reticulum", "Reticuli"},
    {"Scl", "Sculptor", "Sculptoris"},
    {"Sco", "Scorpius", "Scorpii"},
    {"Sct", "Scutum", "Scuti"},
    {"Ser", "Serpens", "Serpentis"},
    {"Sex", "Sextans", "Sextantis"},
    {"Sge", "Sagitta", "Sagittae"},
    {"Sgr", "Sagittarius", "Sagittarii"},
    {"Tau", "Taurus", "Tauri"},
    {"Tel", "Telescopium", "Telescopii"},
    {"TrA", "Triangulum Australe", "Trianguli Australis"},
    {"Tri", "Triangulum", "Trianguli"},
    {"Tuc", "Tucana", "Tucanae"},
    {"UMa", "Ursa Major", "Ursae Majoris"},
    {"UMi", "Ursa Minor", "Ursae Minoris"},
    {"Vel", "Vela", "Velorum"},
    {"Vir", "Virgo", "Virginis"},
    {"Vol", "Volans", "Volantis"},
    {"Vul", "Vulpecula", "Vulpeculae"}
  }; // end _names


}//end class BuildConstellations