Package org.apache.blur.analysis.type.spatial

Source Code of org.apache.blur.analysis.type.spatial.ShapeReadWriter

/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.blur.analysis.type.spatial;

import com.spatial4j.core.context.SpatialContext;
import com.spatial4j.core.distance.DistanceUtils;
import com.spatial4j.core.exception.InvalidShapeException;
import com.spatial4j.core.io.ParseUtils;
import com.spatial4j.core.shape.Circle;
import com.spatial4j.core.shape.Point;
import com.spatial4j.core.shape.Rectangle;
import com.spatial4j.core.shape.Shape;

import java.text.NumberFormat;
import java.util.Locale;
import java.util.StringTokenizer;

/**
* Reads and writes {@link Shape}s to strings.
*/
public class ShapeReadWriter<CTX extends SpatialContext> {
  protected CTX ctx;

  @SuppressWarnings("unchecked")
  public ShapeReadWriter(SpatialContext ctx) {
    this.ctx = (CTX) ctx;
  }

  /**
   * Reads a shape from a given string (ie, X Y, XMin XMax... WKT)
   * <ul>
   * <li>Point: X Y <br />
   * 1.23 4.56</li>
   * <li>BOX: XMin YMin XMax YMax <br />
   * 1.23 4.56 7.87 4.56</li>
   * <li><a href="http://en.wikipedia.org/wiki/Well-known_text"> WKT (Well Known
   * Text)</a> <br />
   * POLYGON( ... ) <br />
   * <b>Note:</b>Polygons and WKT might not be supported by this spatial
   * context; you'll have to use
   * {@link com.spatial4j.core.context.jts.JtsSpatialContext}.</li>
   * </ul>
   *
   * @param value
   *          A string representation of the shape; not null.
   * @return A Shape; not null.
   *
   * @see #writeShape
   */
  public Shape readShape(String value) throws InvalidShapeException {
    Shape s = readStandardShape(value);
    if (s == null) {
      throw new InvalidShapeException("Unable to read: " + value);
    }
    return s;
  }

  /**
   * Writes a shape to a String, in a format that can be read by
   * {@link #readShape(String)}.
   *
   * @param shape
   *          Not null.
   * @return Not null.
   */
  public String writeShape(Shape shape) {
    return writeShape(shape, makeNumberFormat(6));
  }

  /** Overloaded to provide a number format. */
  public String writeShape(Shape shape, NumberFormat nf) {
    if (shape instanceof Point) {
      Point point = (Point) shape;
      return nf.format(point.getX()) + " " + nf.format(point.getY());
    } else if (shape instanceof Rectangle) {
      Rectangle rect = (Rectangle) shape;
      return nf.format(rect.getMinX()) + " " + nf.format(rect.getMinY()) + " " + nf.format(rect.getMaxX()) + " "
          + nf.format(rect.getMaxY());
    } else if (shape instanceof Circle) {
      Circle c = (Circle) shape;
      return "Circle(" + nf.format(c.getCenter().getX()) + " " + nf.format(c.getCenter().getY()) + " " + "d="
          + nf.format(c.getRadius()) + ")";
    }
    return shape.toString();
  }

  /**
   * A convenience method to create a suitable NumberFormat for writing numbers.
   */
  public static NumberFormat makeNumberFormat(int fractionDigits) {
    NumberFormat nf = NumberFormat.getInstance(Locale.ROOT);// not thread-safe
    nf.setGroupingUsed(false);
    nf.setMaximumFractionDigits(fractionDigits);
    nf.setMinimumFractionDigits(fractionDigits);
    return nf;
  }

  protected Shape readStandardShape(String str) {
    if (str == null || str.length() == 0) {
      throw new InvalidShapeException(str);
    }

    if (Character.isLetter(str.charAt(0))) {
      if (str.startsWith("Circle(") || str.startsWith("CIRCLE(")) {
        int idx = str.lastIndexOf(')');
        if (idx > 0) {
          String body = str.substring("Circle(".length(), idx);
          StringTokenizer st = new StringTokenizer(body, " ");
          String token = st.nextToken();
          Point pt;
          if (token.indexOf(',') != -1) {
            pt = readLatCommaLonPoint(token);
          } else {
            double x = Double.parseDouble(token);
            double y = Double.parseDouble(st.nextToken());
            pt = ctx.makePoint(x, y);
          }
          Double d = null;

          String arg = st.nextToken();
          idx = arg.indexOf('=');
          if (idx > 0) {
            String k = arg.substring(0, idx);
            if (k.equals("d") || k.equals("distance")) {
              d = parseDistance(arg.substring(idx + 1));
            } else {
              throw new InvalidShapeException("unknown arg: " + k + " :: " + str);
            }
          } else {
            d = parseDistance(arg);
          }
          if (st.hasMoreTokens()) {
            throw new InvalidShapeException("Extra arguments: " + st.nextToken() + " :: " + str);
          }
          if (d == null) {
            throw new InvalidShapeException("Missing Distance: " + str);
          }
          // NOTE: we are assuming the units of 'd' is the same as that of the
          // spatial context.
          return ctx.makeCircle(pt, d);
        }
      }
      return null;
    }

    if (str.indexOf(',') != -1)
      return readLatCommaLonPoint(str);
    StringTokenizer st = new StringTokenizer(str, " ");
    double p0 = Double.parseDouble(st.nextToken());
    double p1 = Double.parseDouble(st.nextToken());
    if (st.hasMoreTokens()) {
      double p2 = Double.parseDouble(st.nextToken());
      double p3 = Double.parseDouble(st.nextToken());
      if (st.hasMoreTokens())
        throw new InvalidShapeException("Only 4 numbers supported (rect) but found more: " + str);
      return ctx.makeRectangle(p0, p2, p1, p3);
    }
    return ctx.makePoint(p0, p1);
  }

  private static Double parseDistance(String distanceString) {
    distanceString = distanceString.toLowerCase();
    if (distanceString.endsWith("km")) {
      double distanceInKm = Double.parseDouble(distanceString.substring(0, distanceString.length() - 2));
      return DistanceUtils.dist2Degrees(distanceInKm, DistanceUtils.EARTH_MEAN_RADIUS_KM);
    } else if (distanceString.endsWith("m")) {
      double distanceInM = Double.parseDouble(distanceString.substring(0, distanceString.length() - 2));
      double distanceInKm = distanceInM * DistanceUtils.MILES_TO_KM;
      return DistanceUtils.dist2Degrees(distanceInKm, DistanceUtils.EARTH_MEAN_RADIUS_KM);
    }
    return Double.parseDouble(distanceString);
  }

  /** Reads geospatial latitude then a comma then longitude. */
  private Point readLatCommaLonPoint(String value) throws InvalidShapeException {
    double[] latLon = ParseUtils.parseLatitudeLongitude(value);
    return ctx.makePoint(latLon[1], latLon[0]);
  }
}
TOP

Related Classes of org.apache.blur.analysis.type.spatial.ShapeReadWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.