Beispiel #1
0
  /**
   * Finds similar function names and throws an error message.
   *
   * @param name function name
   * @param ii input info
   * @throws QueryException query exception
   */
  public void funError(final QNm name, final InputInfo ii) throws QueryException {
    // find global function
    Functions.get().error(name, ii);

    // find similar local function
    final Levenshtein ls = new Levenshtein();
    final byte[] nm = lc(name.local());
    for (final UserFunc f : funcs) {
      if (ls.similar(nm, lc(f.name.local()), 0)) {
        FUNSIMILAR.thrw(ii, name.string(), f.name.string());
      }
    }
  }
Beispiel #2
0
  /**
   * Adds a local function.
   *
   * @param fun function instance
   * @param ii input info
   * @return function id
   * @throws QueryException query exception
   */
  public int add(final UserFunc fun, final InputInfo ii) throws QueryException {
    final QNm name = fun.name;
    final byte[] uri = name.uri();
    if (uri.length == 0) FUNNONS.thrw(ii, name.string());

    if (NSGlobal.reserved(uri)) {
      if (fun.declared) NAMERES.thrw(ii, name.string());
      funError(name, ii);
    }

    final byte[] ln = name.local();
    for (int l = 0; l < funcs.length; ++l) {
      final QNm qn = funcs[l].name;
      final byte[] u = qn.uri();
      final byte[] nm = qn.local();

      if (eq(ln, nm) && eq(uri, u) && fun.args.length == funcs[l].args.length) {
        // declare function that has been called before
        if (!funcs[l].declared) {
          funcs[l] = fun;
          return l;
        }
        // duplicate declaration
        FUNCDEFINED.thrw(ii, fun.name.string());
      }
    }
    // add function skeleton
    funcs = Array.add(funcs, fun);
    calls = Array.add(calls, new UserFuncCall[0]);
    return funcs.length - 1;
  }
Beispiel #3
0
  /**
   * Returns the specified function.
   *
   * @param name function qname
   * @param args optional arguments
   * @param ii input info
   * @return function instance
   * @throws QueryException query exception
   */
  public StandardFunc get(final QNm name, final Expr[] args, final InputInfo ii)
      throws QueryException {

    final int id = id(name.id());
    if (id == 0) return null;

    // create function
    final Function fl = funcs[id];
    if (!eq(fl.uri(), name.uri())) return null;

    final StandardFunc f = fl.get(ii, args);
    // check number of arguments
    if (args.length < fl.min || args.length > fl.max) XPARGS.thrw(ii, fl);
    return f;
  }
Beispiel #4
0
  /**
   * Reads an element as a gml node. Returns a geometry element or {@code null} if the element does
   * not match one of the specified types.
   *
   * @param node xml node containing gml object(s)
   * @param names allowed geometry types
   * @return geometry, or {@code null}
   * @throws QueryException query exception
   */
  private static Geometry geo(final ANode node, final QNm... names) throws QueryException {
    if (node.type != NodeType.ELM) throw EXPTYPE_X_X_X.get(null, NodeType.ELM, node.type, node);

    final QNm qname = node.qname();
    for (final QNm geo : names) {
      if (!qname.eq(geo)) continue;
      // type found... create reader and geometry element
      try {
        final String input = node.serialize().toString();
        final GMLReader gmlReader = new GMLReader();
        final GeometryFactory geoFactory = new GeometryFactory();
        return gmlReader.read(input, geoFactory);
      } catch (final Throwable ex) {
        throw GeoErrors.gmlReaderErr(ex);
      }
    }
    return null;
  }
Beispiel #5
0
 /**
  * Throws an error if one of the pre-defined functions is similar to the specified function name.
  *
  * @param name function name
  * @param ii input info
  * @throws QueryException query exception
  */
 public void error(final QNm name, final InputInfo ii) throws QueryException {
   // compare specified name with names of predefined functions
   final byte[] ln = name.local();
   final Levenshtein ls = new Levenshtein();
   for (int k = 1; k < size; ++k) {
     final int i = indexOf(keys[k], '}');
     final byte[] u = substring(keys[k], 2, i);
     final byte[] l = substring(keys[k], i + 1);
     if (eq(ln, l)) {
       final byte[] ur = name.uri();
       FUNSIMILAR.thrw(
           ii,
           new TokenBuilder(NSGlobal.prefix(ur)).add(':').add(l),
           new TokenBuilder(NSGlobal.prefix(u)).add(':').add(l));
     } else if (ls.similar(ln, l, 0)) {
       FUNSIMILAR.thrw(ii, name.string(), l);
     }
   }
 }
Beispiel #6
0
  /**
   * Parses a jar descriptor.
   *
   * @param io XML input
   * @return jar descriptor container
   * @throws QueryException query exception
   */
  public JarDesc parse(final IO io) throws QueryException {
    final JarDesc desc = new JarDesc();
    try {
      final ANode node = new DBNode(io).children().next();
      for (final ANode next : node.children()) {
        if (next.type != NodeType.ELM) continue;

        final QNm name = next.qname();
        // ignore namespace to improve compatibility
        if (eq(JAR, name.local())) desc.jars.add(next.string());
        else if (eq(CLASS, name.local())) desc.classes.add(next.string());
        // [CG] Packaging: add warning if unknown elements are encountered
      }
      if (desc.jars.isEmpty()) throw BXRE_JARDESC_X.get(info, NOJARS);
      else if (desc.classes.isEmpty()) throw BXRE_JARDESC_X.get(info, NOCLASSES);
      return desc;
    } catch (final IOException ex) {
      throw BXRE_JARFAIL_X.get(info, ex);
    }
  }
Beispiel #7
0
  /**
   * Returns a new Java function instance.
   *
   * @param name function name
   * @param args arguments
   * @param qc query context
   * @param sc static context
   * @param ii input info
   * @return Java function or {@code null}
   * @throws QueryException query exception
   */
  static JavaMapping get(
      final QNm name,
      final Expr[] args,
      final QueryContext qc,
      final StaticContext sc,
      final InputInfo ii)
      throws QueryException {

    final byte[] uri = name.uri();
    // check if URI starts with "java:" prefix (if yes, module must be Java code)
    final boolean java = startsWith(uri, JAVAPREF);

    // rewrite function name: convert dashes to upper-case initials
    final String local = camelCase(string(name.local()));

    // check imported Java modules
    final String path = camelCase(toPath(java ? substring(uri, JAVAPREF.length) : uri));

    final ModuleLoader modules = qc.resources.modules();
    final Object jm = modules.findImport(path);
    if (jm != null) {
      final Method meth = getModMethod(jm, path, local, args.length, qc, ii);
      if (meth != null) return new JavaModuleFunc(sc, ii, jm, meth, args);
    }

    // only allowed with administrator permissions
    if (!qc.context.user.has(Perm.ADMIN)) return null;

    // check addressed class
    try {
      return new JavaFunc(sc, ii, modules.findClass(path), local, args);
    } catch (final ClassNotFoundException ex) {
      // only throw exception if "java:" prefix was explicitly specified
      if (java) throw FUNCJAVA_X.get(ii, path);
    } catch (final Throwable th) {
      throw JAVAINIT_X.get(ii, th);
    }

    // no function found
    return null;
  }
Beispiel #8
0
  /**
   * Returns an instance of a with the specified name and number of arguments, or {@code null}.
   *
   * @param name name of the function
   * @param args optional arguments
   * @param dyn compile-/run-time flag
   * @param ctx query context
   * @param ii input info
   * @return function instance
   * @throws QueryException query exception
   */
  public static TypedFunc get(
      final QNm name,
      final Expr[] args,
      final boolean dyn,
      final QueryContext ctx,
      final InputInfo ii)
      throws QueryException {

    // get namespace and local name
    // parse data type constructors
    if (eq(name.uri(), XSURI)) {
      final byte[] ln = name.local();
      final AtomType type = AtomType.find(name, false);
      if (type == null) {
        final Levenshtein ls = new Levenshtein();
        for (final AtomType t : AtomType.values()) {
          if (t.par != null
              && t != AtomType.NOT
              && t != AtomType.AAT
              && t != AtomType.BIN
              && ls.similar(lc(ln), lc(t.string()), 0))
            FUNSIMILAR.thrw(ii, name.string(), t.string());
        }
      }
      // no constructor function found, or abstract type specified
      if (type == null || type == AtomType.NOT || type == AtomType.AAT) {
        FUNCUNKNOWN.thrw(ii, name.string());
      }

      if (args.length != 1) FUNCTYPE.thrw(ii, name.string());
      final SeqType to = SeqType.get(type, Occ.ZERO_ONE);
      return TypedFunc.constr(new Cast(ii, args[0], to), to);
    }

    // pre-defined functions
    final StandardFunc fun = Functions.get().get(name, args, ii);
    if (fun != null) {
      if (!ctx.sc.xquery3 && fun.xquery3()) FEATURE30.thrw(ii);
      for (final Function f : Function.UPDATING) {
        if (fun.sig == f) {
          ctx.updating(true);
          break;
        }
      }
      return new TypedFunc(fun, fun.sig.type(args.length));
    }

    // user-defined function
    final TypedFunc tf = ctx.funcs.get(name, args, ii);
    if (tf != null) return tf;

    // Java function (only allowed with administrator permissions)
    final JavaMapping jf = JavaMapping.get(name, args, ctx, ii);
    if (jf != null) return TypedFunc.java(jf);

    // add user-defined function that has not been declared yet
    if (!dyn && FuncType.find(name) == null) return ctx.funcs.add(name, args, ii, ctx);

    // no function found
    return null;
  }
Beispiel #9
0
/**
 * This module contains geo spatial functions for the Geo module.
 *
 * @author BaseX Team 2005-14, BSD License
 * @author Masoumeh Seydi
 */
public final class Geo extends QueryModule {
  /** GML URI. */
  private static final byte[] URI = token("http://www.opengis.net/gml");
  /** Prefix: "gml". */
  private static final String GML = "gml";

  /** QName gml:Point. */
  private static final QNm Q_GML_POINT = QNm.get(GML, "Point", URI);
  /** QName gml:MultiPoint. */
  private static final QNm Q_GML_MULTIPOINT = QNm.get(GML, "MultiPoint", URI);
  /** QName gml:LineString. */
  private static final QNm Q_GML_LINESTRING = QNm.get(GML, "LineString", URI);
  /** QName gml:LinearRing. */
  private static final QNm Q_GML_LINEARRING = QNm.get(GML, "LinearRing", URI);
  /** QName gml:Polygon. */
  private static final QNm Q_GML_POLYGON = QNm.get(GML, "Polygon", URI);
  /** QName gml:MultiPolygon. */
  private static final QNm Q_GML_MULTIPOLYGON = QNm.get(GML, "MultiPolygon", URI);
  /** QName gml:MultiLineString. */
  private static final QNm Q_GML_MULTILINESTRING = QNm.get(GML, "MultiLineString", URI);

  /** Array containing all QNames. */
  private static final QNm[] QNAMES = {
    Q_GML_POINT,
    Q_GML_LINESTRING,
    Q_GML_POLYGON,
    Q_GML_MULTIPOINT,
    Q_GML_MULTILINESTRING,
    Q_GML_MULTIPOLYGON,
    Q_GML_LINEARRING
  };

  /**
   * Returns the dimension of an item.
   *
   * @param node xml element containing gml object(s)
   * @return dimension
   * @throws QueryException query exception
   */
  @Deterministic
  public Int dimension(final ANode node) throws QueryException {
    return Int.get(checkGeo(node).getDimension());
  }

  /**
   * Returns the name of the geometry type in the GML namespace, or the empty sequence.
   *
   * @param node xml element containing gml object(s)
   * @return geometry type
   * @throws QueryException query exception
   */
  @Deterministic
  public QNm geometryType(final ANode node) throws QueryException {
    return new QNm(GML + ':' + checkGeo(node).getGeometryType(), URI);
  }

  /**
   * Returns the name of the geometry type in the GML namespace, or the empty sequence.
   *
   * @param node xml element containing gml object(s)
   * @return integer value of CRS of the geometry
   * @throws QueryException query exception
   */
  @Deterministic
  public Uri srid(final ANode node) throws QueryException {
    return Uri.uri(token(checkGeo(node).getSRID()));
  }

  /**
   * Returns the gml:Envelope of the specified geometry. The envelope is the minimum bounding box of
   * this geometry.
   *
   * @param node xml element containing gml object(s)
   * @return envelop element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode envelope(final ANode node) throws QueryException {
    return gmlWriter(checkGeo(node).getEnvelope());
  }

  /**
   * Returns the WKT format of a geometry.
   *
   * @param node xml element containing gml object(s)
   * @return Well-Known Text geometry representation
   * @throws QueryException query exception
   */
  @Deterministic
  public Str asText(final ANode node) throws QueryException {
    return Str.get(new WKTWriter().write(checkGeo(node)));
  }

  /**
   * Returns the WKB format of a geometry.
   *
   * @param node xml element containing gml object(s)
   * @return Well-Known Binary geometry representation
   * @throws QueryException query exception
   */
  @Deterministic
  public B64 asBinary(final ANode node) throws QueryException {
    return new B64(new WKBWriter().write(checkGeo(node)));
  }

  /**
   * Returns a boolean value which shows if the specified geometry is empty or not.
   *
   * @param node xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln isEmpty(final ANode node) throws QueryException {
    return Bln.get(node != null && checkGeo(node) != null);
  }

  /**
   * Returns a boolean value which shows if the specified geometry is simple or not, which has no
   * anomalous geometric points, such as self intersection or self tangency.
   *
   * @param node xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln isSimple(final ANode node) throws QueryException {
    return Bln.get(checkGeo(node).isSimple());
  }

  /**
   * Returns the boundary of the geometry, in GML. The return value is a sequence of either
   * gml:Point or gml:LinearRing elements.
   *
   * @param node xml element containing gml object(s)
   * @return boundary element (geometry)
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode boundary(final ANode node) throws QueryException {
    return gmlWriter(checkGeo(node).getBoundary());
  }

  /**
   * Returns a boolean value that shows if two geometries are equal or not.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln equals(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Bln.get(geo1.equals(geo2));
  }

  /**
   * Returns a boolean value that shows if this geometry is disjoint to another geometry.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln disjoint(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Bln.get(geo1.disjoint(geo2));
  }

  /**
   * Returns a boolean value that shows if this geometry intersects another geometry.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln intersects(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Bln.get(geo1.intersects(geo2));
  }

  /**
   * Returns a boolean value that shows if this geometry touches the specified geometry.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln touches(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Bln.get(geo1.touches(geo2));
  }

  /**
   * Returns a boolean value that shows if this geometry crosses the specified geometry.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln crosses(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Bln.get(geo1.crosses(geo2));
  }

  /**
   * Returns a boolean value that shows if this geometry is within the specified geometry.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln within(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Bln.get(geo1.within(geo2));
  }

  /**
   * Returns a boolean value that shows if this geometry contains the specified geometry.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln contains(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Bln.get(geo1.contains(geo2));
  }

  /**
   * Returns a boolean value that shows if this geometry overlaps the specified geometry.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln overlaps(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Bln.get(geo1.overlaps(geo2));
  }

  /**
   * Returns a boolean value that shows if whether relationships between the boundaries, interiors
   * and exteriors of two geometries match the pattern specified in intersection-matrix-pattern.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @param intersectionMatrix intersection matrix for two geometries
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln relate(final ANode node1, final ANode node2, final Str intersectionMatrix)
      throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Bln.get(geo1.relate(geo2, intersectionMatrix.toJava()));
  }

  /**
   * Returns the shortest distance in the units of the spatial reference system of geometry, between
   * the geometries. The distance is the distance between a point on each of the geometries.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return distance double value
   * @throws QueryException query exception
   */
  @Deterministic
  public Dbl distance(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return Dbl.get(geo1.distance(geo2));
  }

  /**
   * Returns a polygon that represents all Points whose distance from this geometric object is less
   * than or equal to distance. The returned element must be either gml:Polygon, gml:LineString or
   * gml:Point.
   *
   * @param node xml element containing gml object(s)
   * @param distance specific distance from the $geometry (the buffer width)
   * @return buffer geometry as gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode buffer(final ANode node, final Dbl distance) throws QueryException {
    return gmlWriter(checkGeo(node).buffer(distance.dbl()));
  }

  /**
   * Returns the convex hull geometry of a geometry in GML, or the empty sequence. The returned
   * element must be either gml:Polygon, gml:LineString or gml:Point.
   *
   * @param node xml element containing gml object(s)
   * @return convex hull geometry as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode convexHull(final ANode node) throws QueryException {
    return gmlWriter(checkGeo(node).convexHull());
  }

  /**
   * Returns a geometric object representing the Point set intersection of two geometries.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return intersection geometry as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode intersection(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return gmlWriter(geo1.intersection(geo2));
  }

  /**
   * Returns a geometric object that represents the Point set union of two geometries.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return union geometry as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode union(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return gmlWriter(geo1.union(geo2));
  }

  /**
   * Returns a geometric object that represents the Point set difference of two geometries.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return difference geometry as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode difference(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return gmlWriter(geo1.difference(geo2));
  }

  /**
   * Returns a geometric object that represents the Point set symmetric difference of two
   * geometries.
   *
   * @param node1 xml element containing gml object(s)
   * @param node2 xml element containing gml object(s)
   * @return symmetric difference geometry as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode symDifference(final ANode node1, final ANode node2) throws QueryException {
    final Geometry geo1 = checkGeo(node1);
    final Geometry geo2 = checkGeo(node2);
    return gmlWriter(geo1.symDifference(geo2));
  }

  /**
   * Returns number of geometries in a geometry collection, or 1 if the input is not a collection.
   *
   * @param node xml element containing gml object(s)
   * @return integer value of number of geometries
   * @throws QueryException query exception
   */
  @Deterministic
  public Int numGeometries(final ANode node) throws QueryException {
    return Int.get(checkGeo(node).getNumGeometries());
  }

  /**
   * Returns the nth geometry of a geometry collection, or the geometry if the input is not a
   * collection.
   *
   * @param node xml element containing gml object(s)
   * @param number integer number as the index of nth geometry
   * @return geometry as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode geometryN(final ANode node, final Int number) throws QueryException {
    final Geometry geo = checkGeo(node);
    final long n = number.itr();
    if (n < 1 || n > geo.getNumGeometries()) throw GeoErrors.outOfRangeIdx(number);
    return gmlWriter(geo.getGeometryN((int) n - 1));
  }

  /**
   * Returns the x-coordinate value for point.
   *
   * @param node xml element containing gml object(s)
   * @return x double value
   * @throws QueryException query exception
   */
  @Deterministic
  public Dbl x(final ANode node) throws QueryException {
    final Geometry geo = geo(node, Q_GML_POINT);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Point");

    return Dbl.get(geo.getCoordinate().x);
  }

  /**
   * Returns the y-coordinate value for point.
   *
   * @param node xml element containing gml object(s)
   * @return y double value
   * @throws QueryException query exception
   */
  @Deterministic
  public Dbl y(final ANode node) throws QueryException {
    final Geometry geo = geo(node, Q_GML_POINT);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Point");

    return Dbl.get(geo.getCoordinate().y);
  }

  /**
   * Returns the z-coordinate value for point.
   *
   * @param node xml element containing gml object(s)
   * @return z double value
   * @throws QueryException query exception
   */
  @Deterministic
  public Dbl z(final ANode node) throws QueryException {
    final Geometry geo = geo(node, Q_GML_POINT);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Line");

    return Dbl.get(geo.getCoordinate().z);
  }

  /**
   * Returns the length of this Geometry. Linear geometries return their length. Areal geometries
   * return their parameter. Others return 0.0
   *
   * @param node xml element containing gml object(s)
   * @return length double value
   * @throws QueryException query exception
   */
  @Deterministic
  public Dbl length(final ANode node) throws QueryException {
    return Dbl.get(checkGeo(node).getLength());
  }

  /**
   * Returns the start point of a line.
   *
   * @param node xml element containing gml object(s)
   * @return start point geometry as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode startPoint(final ANode node) throws QueryException {
    final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Line");

    return gmlWriter(((LineString) geo).getStartPoint());
  }

  /**
   * Returns the end point of a line.
   *
   * @param node xml element containing gml object(s)
   * @return end point geometry as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode endPoint(final ANode node) throws QueryException {
    final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Line");

    return gmlWriter(((LineString) geo).getEndPoint());
  }

  /**
   * Checks if the line is closed loop. That is, if the start Point is same with end Point.
   *
   * @param node xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln isClosed(final ANode node) throws QueryException {
    final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING, Q_GML_MULTILINESTRING);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Line");

    return Bln.get(
        geo instanceof LineString
            ? ((LineString) geo).isClosed()
            : ((MultiLineString) geo).isClosed());
  }

  /**
   * Return a boolean value that shows weather the line is a ring or not. A line is a ring if it is
   * closed and simple.
   *
   * @param node xml element containing gml object(s)
   * @return boolean value
   * @throws QueryException query exception
   */
  @Deterministic
  public Bln isRing(final ANode node) throws QueryException {
    final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Line");

    return Bln.get(((LineString) geo).isRing());
  }

  /**
   * Returns the number of points in a geometry.
   *
   * @param node xml element containing gml object(s)
   * @return number of points int value
   * @throws QueryException query exception
   */
  @Deterministic
  public Int numPoints(final ANode node) throws QueryException {
    return Int.get(checkGeo(node).getNumPoints());
  }

  /**
   * Returns the nth point of a line.
   *
   * @param node xml element containing gml object(s)
   * @param number index of i-th point
   * @return n-th point as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode pointN(final ANode node, final Int number) throws QueryException {
    final Geometry geo = geo(node, Q_GML_LINEARRING, Q_GML_LINESTRING);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Line");

    final int max = geo.getNumPoints();
    final long n = number.itr();
    if (n < 1 || n > max) throw GeoErrors.outOfRangeIdx(number);

    return gmlWriter(((LineString) geo).getPointN((int) n - 1));
  }

  /**
   * Returns the area of a Geometry. Areal Geometries have a non-zero area. Returns zero for Point
   * and Lines.
   *
   * @param node xml element containing gml object(s)
   * @return geometry area as a double vaue
   * @throws QueryException query exception
   */
  @Deterministic
  public Dbl area(final ANode node) throws QueryException {
    return Dbl.get(checkGeo(node).getArea());
  }

  /**
   * Returns the mathematical centroid of the geometry as a gml:Point. The point is not guaranteed
   * to be on the surface.
   *
   * @param node xml element containing gml object(s)
   * @return centroid geometry as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode centroid(final ANode node) throws QueryException {
    return gmlWriter(checkGeo(node).getCentroid());
  }

  /**
   * Returns a gml:Point that is interior of this geometry. If it cannot be inside the geometry,
   * then it will be on the boundary.
   *
   * @param node xml element containing gml object(s)
   * @return a point as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode pointOnSurface(final ANode node) throws QueryException {
    return gmlWriter(checkGeo(node).getInteriorPoint());
  }

  /**
   * Returns the outer ring of a polygon, in GML.
   *
   * @param node xml element containing gml object(s)
   * @return exterior ring geometry (LineString) as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode exteriorRing(final ANode node) throws QueryException {
    final Geometry geo = geo(node, Q_GML_POLYGON);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Polygon");

    return gmlWriter(((Polygon) geo).getExteriorRing());
  }

  /**
   * Returns the number of interior rings in a polygon.
   *
   * @param node xml element containing gml object(s)
   * @return integer number of interior rings
   * @throws QueryException query exception
   */
  @Deterministic
  public Int numInteriorRing(final ANode node) throws QueryException {
    final Geometry geo = geo(node, Q_GML_POLYGON);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Polygon");

    return Int.get(((Polygon) geo).getNumInteriorRing());
  }

  /**
   * Returns the nth geometry of a geometry collection.
   *
   * @param node xml element containing gml object(s)
   * @param number index of i-th interior ring
   * @return n-th interior ring geometry (LineString) as a gml element
   * @throws QueryException query exception
   */
  @Deterministic
  public ANode interiorRingN(final ANode node, final Int number) throws QueryException {
    final Geometry geo = geo(node, Q_GML_POLYGON);
    if (geo == null && checkGeo(node) != null)
      throw GeoErrors.geoType(node.qname().local(), "Polygon");

    final long n = number.itr();
    final int max = ((Polygon) geo).getNumInteriorRing();
    if (n < 1 || n > max) throw GeoErrors.outOfRangeIdx(number);
    return gmlWriter(((Polygon) geo).getInteriorRingN((int) n - 1));
  }

  // PRIVATE METHODS (hidden from user of module) ========================================

  /**
   * Reads an element as a gml node. Returns a geometry element or throws an exception if the
   * element is of the wrong type.
   *
   * @param node xml node containing gml object(s)
   * @return geometry
   * @throws QueryException query exception
   */
  private Geometry checkGeo(final ANode node) throws QueryException {
    final Geometry geo = geo(node, QNAMES);
    if (geo == null) throw GeoErrors.unrecognizedGeo(node.qname().local());
    return geo;
  }

  /**
   * Reads an element as a gml node. Returns a geometry element or {@code null} if the element does
   * not match one of the specified types.
   *
   * @param node xml node containing gml object(s)
   * @param names allowed geometry types
   * @return geometry, or {@code null}
   * @throws QueryException query exception
   */
  private static Geometry geo(final ANode node, final QNm... names) throws QueryException {
    if (node.type != NodeType.ELM) throw EXPTYPE_X_X_X.get(null, NodeType.ELM, node.type, node);

    final QNm qname = node.qname();
    for (final QNm geo : names) {
      if (!qname.eq(geo)) continue;
      // type found... create reader and geometry element
      try {
        final String input = node.serialize().toString();
        final GMLReader gmlReader = new GMLReader();
        final GeometryFactory geoFactory = new GeometryFactory();
        return gmlReader.read(input, geoFactory);
      } catch (final Throwable ex) {
        throw GeoErrors.gmlReaderErr(ex);
      }
    }
    return null;
  }

  /**
   * Writes an geometry and returns a string representation of the geometry.
   *
   * @param geometry geometry
   * @return DBNode database node
   * @throws QueryException exception
   */
  private DBNode gmlWriter(final Geometry geometry) throws QueryException {
    final String geo;
    try {
      // write geometry and add namespace declaration
      geo =
          new GMLWriter()
              .write(geometry)
              .replaceAll("^<gml:(.*?)>", "<gml:$1 xmlns:gml='" + string(URI) + "'>");
    } catch (final Exception ex) {
      throw GeoErrors.gmlWriterErr(ex);
    }

    try {
      final IO io = new IOContent(geo);
      return new DBNode(MemBuilder.build(new XMLParser(io, queryContext.context.options)));
    } catch (final IOException ex) {
      throw IOERR_X.get(null, ex);
    }
  }
}
Beispiel #10
0
 /**
  * Returns an index to the specified function, or {@code -1}.
  *
  * @param name name of the function
  * @param args optional arguments
  * @return function instance
  */
 private int indexOf(final QNm name, final Expr[] args) {
   for (int id = 0; id < funcs.length; ++id) {
     if (name.eq(funcs[id].name) && args.length == funcs[id].args.length) return id;
   }
   return -1;
 }
Beispiel #11
0
 /**
  * Checks if the specified item is a string or element.
  *
  * @param it item to be checked
  * @return item
  * @throws QueryException query exception
  */
 private Item checkElmStr(final Item it) throws QueryException {
   if (it instanceof AStr || TEST.eq(it)) return it;
   throw ELMSTRTYPE.thrw(info, Q_ENTRY.string(), it.type);
 }