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

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

The newest version!
/*
 * Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
 * See LICENSE for license information.
 */

package ucar.unidata.geoloc.ogc;

import java.util.HashMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ucar.nc2.units.SimpleUnit;
import ucar.unidata.geoloc.ProjectionImpl;
import ucar.unidata.geoloc.projection.*;
import java.text.ParseException;

/**
 * This class parses OGC WKT Spatial Reference Text.
 *
 * @author Barrodale Computing Services, Ltd. (Eric Davies)
 * @author Unidata Java Development Team
 * @deprecated will move in ver6
 */
@Deprecated
public class WKTParser {
  private static Logger logger = LoggerFactory.getLogger(WKTParser.class);

  /*
   * 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 HashMap parameters = new HashMap<>();

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

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

  /**
   * parse position
   */
  private int position;

  /**
   * 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);
    }
  }

  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);
    }

  }

  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);
      }
    }
  }

  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);
    }
  }

  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();
  }

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

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

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

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

  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();
        switch (term) {
          case "PARAMETER":
            eatParameter();
            break;
          case "UNIT":
            eatProjcsUnit();
            break;
          case "PROJECTION":
            eatProjectionType();
            break;
        }
      }
    }
  }

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

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

  private void eatProjectionType() throws ParseException {
    eatOpenBrace();
    projectionType = eatString();
    eatCloseBrace();
  }

  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();
        switch (term) {
          case "DATUM":
            eatDatum();
            break;
          case "PRIMEM":
            eatPrimem();
            break;
          case "UNIT":
            eatUnit();
            break;
        }
      }
    }
  }

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

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

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

  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.containsKey(name.toLowerCase()));
  }


  /**
   * 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 = parameters.get(name.toLowerCase());
    if (val == null) {
      throw new IllegalArgumentException("no parameter called " + name);
    }
    return val;
  }

  /**
   * 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.
   */
  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) {
            logger.warn("{} {} not convertible to km", srp.getProjUnitValue(), srp.getProjUnitName());
          }
        }
        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);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy