All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ucar.unidata.geoloc.ogc.WKTParser Maven / Gradle / Ivy

Go to download

The NetCDF-Java Library is a Java interface to NetCDF files, as well as to many other types of scientific data formats.

The newest version!
/*
 * Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
 *
 * Portions of this software were developed by the Unidata Program at the
 * University Corporation for Atmospheric Research.
 *
 * Access and use of this software shall impose the following obligations
 * and understandings on the user. The user is granted the right, without
 * any fee or cost, to use, copy, modify, alter, enhance and distribute
 * this software, and any derivative works thereof, and its supporting
 * documentation for any purpose whatsoever, provided that this entire
 * notice appears in all copies of the software, derivative works and
 * supporting documentation.  Further, UCAR requests that the user credit
 * UCAR/Unidata in any publications that result from the use of this
 * software or in any product that includes this software. The names UCAR
 * and/or Unidata, however, may not be used in any advertising or publicity
 * to endorse or promote any products or commercial entity unless specific
 * written permission is obtained from UCAR/Unidata. The user also
 * understands that UCAR/Unidata is not obligated to provide the user with
 * any support, consulting, training or assistance of any kind with regard
 * to the use, operation and performance of this software nor to provide
 * the user with any updates, revisions, new versions or "bug fixes."
 *
 * THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
 * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
 * WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package ucar.unidata.geoloc.ogc;

import ucar.nc2.units.SimpleUnit;

import ucar.nc2.util.IO;
import ucar.unidata.geoloc.ProjectionImpl;
import ucar.unidata.geoloc.projection.*;

import java.io.IOException;
import java.text.ParseException;

/**
 * This class parses OGC WKT Spatial Reference Text.
 *
 * @author Barrodale Computing Services, Ltd. (Eric Davies)
 * @author Unidata Java Development Team
 */
public class WKTParser {

  /*
  * geogcs info
  */

  /**
   * geo coord sys name
   */
  private String geogcsName;

  /**
   * datum name
   */
  private String datumName;

  /**
   * spheriod name
   */
  private String spheroidName;

  /**
   * major axis, inverse minor axis
   */
  private double majorAxis, inverseMinor;

  /**
   * primeMeridian name
   */
  private String primeMeridianName;

  /**
   * primeMeridian name
   */
  private double primeMeridianValue;

  /**
   * geographic unit name
   */
  private String geogUnitName;

  /**
   * geographic unit value
   */
  private double geogUnitValue;

  /**
   * is this a projection
   */
  private boolean isAProjection;

  /**
   * projection name
   */
  private String projName;

  /**
   * projection type
   */
  private String projectionType;

  /**
   * projection parameters
   */
  private java.util.HashMap parameters = new java.util.HashMap();

  /**
   * projection unit name
   */
  private String projUnitName;

  /**
   * projection unit value
   */
  private double projUnitValue;

  /**
   * parse position
   */
  private int position = 0;

  /**
   * the reader
   */
  java.io.StringReader reader;

  /**
   * Creates a new instance of WKTParser. If the constructor
   * succeeds, the spatial reference text was successfully parsed.
   *
   * @param srtext The spatial reference text to be parsed.
   *               Geocentric coordinate text is not currently supported.
   * @throws ParseException A ParseException is thrown
   *                        if the spatial reference text could not be parsed.
   */
  public WKTParser(String srtext) throws ParseException {
    reader = new java.io.StringReader(srtext);

    if (srtext.startsWith("PROJCS")) {
      isAProjection = true;
      parseProjcs();
    } else {
      isAProjection = false;
      parseGeogcs();
    }
  }

  /**
   * Peek ahead
   *
   * @return the char
   * @throws ParseException problem parsing
   */
  private char peek() throws ParseException {
    try {
      reader.mark(10);
      int aChar = reader.read();
      reader.reset();
      if (aChar < 0) {
        return (char) 0;
      } else {
        return (char) aChar;
      }
    } catch (java.io.IOException e1) {
      throw new ParseException("Strange io error " + e1, position);
    }
  }

  /**
   * _more_
   *
   * @return _more_
   * @throws ParseException _more_
   */
  private char getChar() throws ParseException {
    try {
      int val = reader.read();
      position++;
      if (val < 0) {
        throw new ParseException("unexpected eof of srtext",
                position);
      }
      return (char) val;
    } catch (java.io.IOException e1) {
      throw new ParseException(e1.toString(), position);
    }

  }

  /**
   * _more_
   *
   * @param literal _more_
   * @throws ParseException _more_
   */
  private void eatLiteral(String literal) throws ParseException {
    int n = literal.length();
    for (int i = 0; i < n; i++) {
      char v = getChar();
      if (v != literal.charAt(i)) {
        throw new ParseException("bad srtext", position);
      }
    }
  }

  /**
   * _more_
   *
   * @return _more_
   * @throws ParseException _more_
   */
  private double eatReal() throws ParseException {
    StringBuilder b = new StringBuilder();
    for (; ; ) {
      char t = peek();
      if (Character.isDigit(t) || (t == 'e') || (t == 'E')
              || (t == '.') || (t == '-') || (t == '+')) {
        b.append(getChar());
      } else {
        break;
      }
    }
    try {
      return Double.parseDouble(b.toString());
    } catch (NumberFormatException e1) {
      throw new ParseException("bad number" + e1, position);
    }
  }

  /**
   * _more_
   *
   * @return _more_
   * @throws ParseException _more_
   */
  private String eatString() throws ParseException {
    StringBuilder b = new StringBuilder();
    if (getChar() != '"') {
      throw new ParseException("expected string", position);
    }
    for (; ; ) {
      char t = getChar();
      if (t == '"') {
        break;
      }
      b.append(t);
    }
    return b.toString();
  }


  /**
   * _more_
   *
   * @return _more_
   * @throws ParseException _more_
   */
  private String eatTerm() throws ParseException {
    StringBuilder b = new StringBuilder();
    for (; ; ) {
      char val = peek();
      if (!Character.isJavaIdentifierPart(val)) {
        break;
      }
      b.append(getChar());
    }
    return b.toString();
  }

  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatComma() throws ParseException {
    if (getChar() != ',') {
      throw new ParseException("expected comma", position);
    }
  }

  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatOpenBrace() throws ParseException {
    if (getChar() != '[') {
      throw new ParseException("expected [", position);
    }
  }

  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatCloseBrace() throws ParseException {
    if (getChar() != ']') {
      throw new ParseException("expected ]", position);
    }
  }

  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void parseProjcs() throws ParseException {
    eatLiteral("PROJCS[");
    projName = eatString();
    eatComma();
    parseGeogcs();
    for (; ; ) {
      char next = getChar();
      if (next == ']') {
        break;
      } else if (next != ',') {
        throw new ParseException("expected , or ]", position);
      } else {
        String term = eatTerm();
        if ("PARAMETER".equals(term)) {
          eatParameter();
        } else if ("UNIT".equals(term)) {
          eatProjcsUnit();
        } else if ("PROJECTION".equals(term)) {
          eatProjectionType();
        }
      }
    }
  }


  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatParameter() throws ParseException {
    eatOpenBrace();
    String parameterName = eatString();
    eatComma();
    Double value = eatReal();
    eatCloseBrace();
    parameters.put(parameterName.toLowerCase(), value);
  }


  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatProjcsUnit() throws ParseException {
    eatOpenBrace();
    projUnitName = eatString();
    eatComma();
    projUnitValue = eatReal();
    eatCloseBrace();
  }


  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatProjectionType() throws ParseException {
    eatOpenBrace();
    projectionType = eatString();
    eatCloseBrace();
  }

  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void parseGeogcs() throws ParseException {
    eatLiteral("GEOGCS[");
    geogcsName = eatString();
    for (; ; ) {
      char t = getChar();
      if (t == ']') {
        break;
      } else if (t != ',') {
        throw new ParseException("expected , or ]", position);
      } else {
        String term = eatTerm();
        if ("DATUM".equals(term)) {
          eatDatum();
        } else if ("PRIMEM".equals(term)) {
          eatPrimem();
        } else if ("UNIT".equals(term)) {
          eatUnit();
        }
      }
    }
  }


  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatDatum() throws ParseException {
    eatOpenBrace();
    datumName = eatString();
    eatComma();
    eatSpheroid();
    eatCloseBrace();
  }


  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatPrimem() throws ParseException {
    eatOpenBrace();
    primeMeridianName = eatString();
    eatComma();
    primeMeridianValue = eatReal();
    eatCloseBrace();
  }

  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatSpheroid() throws ParseException {
    eatLiteral("SPHEROID");
    eatOpenBrace();
    spheroidName = eatString();
    eatComma();
    majorAxis = eatReal();
    eatComma();
    inverseMinor = eatReal();
    eatCloseBrace();
  }

  /**
   * _more_
   *
   * @throws ParseException _more_
   */
  private void eatUnit() throws ParseException {
    eatOpenBrace();
    geogUnitName = eatString();
    eatComma();
    geogUnitValue = eatReal();
    eatCloseBrace();
  }


  /**
   * Get the name of the geographic coordinate system.
   *
   * @return the name.
   */
  public String getGeogcsName() {
    return geogcsName;
  }

  /**
   * Get the datum name. Note that the datum name itself implies information
   * not found in the spheroid.
   *
   * @return The name of the datum.
   */
  public String getDatumName() {
    return datumName;
  }

  /**
   * Get the name of the spheroid.
   *
   * @return The name of the spheroid.
   */
  public String getSpheroidName() {
    return spheroidName;
  }

  /**
   * Get the major axis of the spheroid.
   *
   * @return The major axis of the spheroid, in meters.
   */
  public double getMajorAxis() {
    return majorAxis;
  }


  /**
   * Get the inverse flattening.
   *
   * @return The inverse flattening. Note that this is unitless.
   */
  public double getInverseFlattening() {
    return inverseMinor;
  }


  /**
   * Get the name of the prime meridian.
   *
   * @return the name of the prime meridian. Usually "Greenwich".
   */
  public String getPrimeMeridianName() {
    return primeMeridianName;
  }


  /**
   * Return the value of prime meridian.
   *
   * @return The longitude of the prime meridian, usually 0.
   */
  public double getPrimeMeridianValue() {
    return primeMeridianValue;
  }


  /**
   * Get the name of the unit that the prime meridian is expressed in.
   *
   * @return Tje name of the unit that the prime meridian is expressed in. Usually "Degree".
   */
  public String getGeogUnitName() {
    return geogUnitName;
  }


  /**
   * Get the size of the unit that the prime meridian is expressed in.
   *
   * @return The conversion from the prime meridian units to radians.
   */
  public double getGeogUnitValue() {
    return geogUnitValue;
  }


  /**
   * Inquire if a particular projection parameter is present.
   *
   * @param name The name of the parameter. Case is ignored.
   * @return True if the parameter is present.
   */
  public boolean hasParameter(String name) {
    return (parameters.get(name.toLowerCase()) != null);
  }


  /**
   * Get the value of the projection parameter. An IllegalArgument exception
   * is thrown if the parameter is not found.
   *
   * @param name The name of the parameter. Case is ignored.
   * @return The value of the parameter, as a double.
   */
  public double getParameter(String name) {
    Double val = (Double) parameters.get(name.toLowerCase());
    if (val == null) {
      throw new IllegalArgumentException("no parameter called " + name);
    }
    return val.doubleValue();
  }

  /**
   * Determine if the spatial reference text defines a planar projection,
   * as opposed to a Geographic coordinate system.
   *
   * @return True if the spatial reference text defines a planar projection system.
   */
  public boolean isPlanarProjection() {
    return isAProjection;
  }

  /**
   * Get the name of the projection.
   *
   * @return The name of the projection.
   */
  public String getProjName() {
    return projName;
  }

  /**
   * Get the name of the type of projection.
   *
   * @return Returns the name of the type of the projection. For example,Transverse_Mercator.
   *         Returns null for geographic coordinate systems.
   */
  public String getProjectionType() {
    return projectionType;
  }


  /**
   * Get the name of the projection unit.
   *
   * @return Get the name of the projection unit. Usually "Meter".
   */
  public String getProjUnitName() {
    return projUnitName;
  }

  /**
   * Get the projection unit value.
   *
   * @return The size of the projection unit, in meters.
   */
  public double getProjUnitValue() {
    return projUnitValue;
  }


  /**
   * Convert OGC spatial reference WKT to a ProjectionImpl.
   * An IllegalArgumentException may be thrown if a parameter is missing.
   *
   * @param srp The parsed OGC WKT spatial reference text.
   * @return The ProjectionImpl class.
   * @throws java.text.ParseException If the OGIS spatial reference text was not parseable.
   */
  public static ProjectionImpl convertWKTToProjection(WKTParser srp) {
    if (!srp.isPlanarProjection()) {
      return new ucar.unidata.geoloc.projection.LatLonProjection();
    } else {
      String projectionType = srp.getProjectionType();
      double falseEasting = 0;
      double falseNorthing = 0;
      ProjectionImpl proj = null;
      if (srp.hasParameter("False_Easting")) {
        falseEasting = srp.getParameter("False_Easting");
      }
      if (srp.hasParameter("False_Northing")) {
        falseNorthing = srp.getParameter("False_Northing");
      }
      if ((falseEasting != 0.0) || (falseNorthing != 0.0)) {
        double scalef = 1.0;
        if (srp.getProjUnitName() != null) {
          try {
            SimpleUnit unit =
                    SimpleUnit.factoryWithExceptions(
                            srp.getProjUnitName());
            scalef = unit.convertTo(srp.getProjUnitValue(),
                    SimpleUnit.kmUnit);
          } catch (Exception e) {
            System.out.println(srp.getProjUnitValue() + " "
                    + srp.getProjUnitName()
                    + " not convertible to km");
          }
        }
        falseEasting *= scalef;
        falseNorthing *= scalef;
      }

      if (srp.getProjName().contains("UTM_Zone_"))
        return processUTM(srp);

      if ("Transverse_Mercator".equals(projectionType)) {
        double lat0 = srp.getParameter("Latitude_Of_Origin");
        double scale = srp.getParameter("Scale_Factor");
        double tangentLon = srp.getParameter("Central_Meridian");
        proj = new TransverseMercator(lat0, tangentLon, scale, falseEasting, falseNorthing);

      } else if ("Lambert_Conformal_Conic".equals(projectionType)) {
        double lon0 = srp.getParameter("Central_Meridian");
        double par1 = srp.getParameter("Standard_Parallel_1");
        double par2 = par1;
        if (srp.hasParameter("Standard_Parallel_2")) {
          par2 = srp.getParameter("Standard_Parallel_2");
        }
        double lat0 = srp.getParameter("Latitude_Of_Origin");
        return new LambertConformal(lat0, lon0, par1, par2, falseEasting, falseNorthing);

      } else if ("Albers".equals(projectionType)) {
        double lon0 = srp.getParameter("Central_Meridian");
        double par1 = srp.getParameter("Standard_Parallel_1");
        double par2 = par1;
        if (srp.hasParameter("Standard_Parallel_2")) {
          par2 = srp.getParameter("Standard_Parallel_2");
        }
        double lat0 = srp.getParameter("Latitude_Of_Origin");
        return new AlbersEqualArea(lat0, lon0, par1, par2, falseEasting, falseNorthing);

      } else if ("Stereographic".equals(projectionType)) {
        double lont = srp.getParameter("Central_Meridian");
        double scale = srp.getParameter("Scale_Factor");
        double latt = srp.getParameter("Latitude_Of_Origin");
        return new Stereographic(latt, lont, scale, falseEasting, falseNorthing);

      } else if ("Mercator".equals(projectionType)) {
        double lat0 = srp.getParameter("Latitude_Of_Origin");
        double lon0 = srp.getParameter("Central_Meridian");
        proj = new Mercator(lon0, lat0, falseEasting, falseNorthing);

      } else if ("Universal_Transverse_Mercator".equals(projectionType)) {
        //throw new java.text.ParseException(
        //    "UTM adapter not implemented yet", 0);
      }
      return proj;
    }

  }

  static ProjectionImpl processUTM(WKTParser srp) {
  // NAD_1983_UTM_Zone_12N
      String name = srp.getProjName();
      int pos = name.indexOf("UTM_Zone_");
      String zoneS = name.substring(pos + 9);
      char lastC;
      int zone = Integer.parseInt(zoneS.substring(0, zoneS.length()-1));
      lastC = zoneS.charAt(zoneS.length()-1);
      boolean isNorth = (lastC =='N');

      return new UtmProjection(zone, isNorth);
  }

  public static void main(String[] args) throws IOException, ParseException {
    String testFile = "E:/work/yuan/shapefile/SkiAreaBoundaries.prj";
    //String filename = ( args != args[0] == null)  ? testFile : args[0];

    String contents = IO.readFile(testFile);
    System.out.printf("%s%n", contents);

    WKTParser p = new WKTParser(contents);
    ProjectionImpl proj = convertWKTToProjection(p);
    System.out.printf("%s%n", proj);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy