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

edu.ucr.cs.bdlab.beast.geolite.EnvelopeND Maven / Gradle / Ivy

/*
 * Copyright 2018 University of California, Riverside
 *
 * Licensed 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 edu.ucr.cs.bdlab.beast.geolite;

import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.CoordinateFilter;
import org.locationtech.jts.geom.CoordinateSequence;
import org.locationtech.jts.geom.CoordinateSequenceComparator;
import org.locationtech.jts.geom.CoordinateSequenceFilter;
import org.locationtech.jts.geom.CoordinateXY;
import org.locationtech.jts.geom.Dimension;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryComponentFilter;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.GeometryFilter;
import org.locationtech.jts.geom.IntersectionMatrix;
import org.locationtech.jts.geom.Location;

/**
 * A wrapper around EnvelopeNDLite that makes it a JTS geometry.
 */
public class EnvelopeND extends Geometry {
  public void setCoordinateDimension(int numDimensions) {
    envelopeLite.setCoordinateDimension(numDimensions);
    this.envelope = null;
  }

  /**The underlying envelope that stores the information*/
  EnvelopeNDLite envelopeLite;

  public EnvelopeND(GeometryFactory geometryFactory) {
    super(geometryFactory);
    this.envelopeLite = new EnvelopeNDLite();
  }

  public EnvelopeND(GeometryFactory geometryFactory, EnvelopeNDLite envelopeLite) {
    super(geometryFactory);
    this.envelopeLite = envelopeLite;
  }

  /**
   * Create an envelope from a list of coordinates. The passed arguments is a list in the form (x1, y1, z1, ...,
   * x2, y1, z2, ...)
   * @param geometryFactory the factory associated with this geometry
   * @param numDimensions the number of dimensions to initialize to
   * @param args (optional) the coordinates to initialize to. If not set, the envelope is initialized to an
   *             inverse infinite envelope that has the range (+∞, -∞) in all dimensions.
   */
  public EnvelopeND(GeometryFactory geometryFactory, int numDimensions, double ... args) {
    super(geometryFactory);
    envelopeLite = new EnvelopeNDLite(numDimensions, args);
  }

  /**
   * Creates an envelope initialized to the given two corners.
   * @param geometryFactory the geometry factory associated with this geometry
   * @param minCoord the coordinate of the lower corner (on all dimensions and inclusive)
   * @param maxCoord the coordinate of the upper corner (on all dimensions and exclusive)
   */
  public EnvelopeND(GeometryFactory geometryFactory, double[] minCoord, double[] maxCoord) {
    super(geometryFactory);
    envelopeLite = new EnvelopeNDLite(minCoord, maxCoord);
  }

  /**
   * A copy constructor.
   * @param other takes a value from another envelope
   */
  public EnvelopeND(EnvelopeND other) {
    this(other.getFactory());
    this.envelopeLite = new EnvelopeNDLite(other.envelopeLite);
  }

  /**
   * A constructor from JTS Envelope.
   * @param geometryFactory the factory associated with this envelope
   * @param other JTS envelope
   */
  public EnvelopeND(GeometryFactory geometryFactory, Envelope other) {
    super(geometryFactory);
    this.envelopeLite = new EnvelopeNDLite(2, other.getMinX(), other.getMinY(),
        other.getMaxX(), other.getMaxY());
  }

  @Override
  public int getNumPoints() {
    return 4;
  }

  /**
   * Compute the intersection of this envelope and the given envelope and return the result as a new Envelope.
   * @param other the other envelope to test for intersection
   * @return {@code true} if the interior of the two envelopes are not disjoint
   */
  public EnvelopeND intersectionEnvelope(EnvelopeND other) {
    return new EnvelopeND(this.getFactory(), envelopeLite.intersectionEnvelope(other.envelopeLite));
  }

  /**
   * Tests if this envelope intersects the other envelope (not disjoint)
   * @param envelope2 the envelope to test for intersection
   * @return {@code true} if the interior of this and the given envelopes are not disjoint
   */
  public boolean intersectsEnvelope(EnvelopeND envelope2) {
    return this.envelopeLite.intersectsEnvelope(envelope2.envelopeLite);
  }

  public boolean intersectsEnvelope(Envelope envelope2) {
    return this.envelopeLite.intersectsEnvelope(envelope2);
  }

  /**
   * Computes the minimum bounding box (envelope) of this geometry
   * @param envelope (output) the envelope to fill with the information
   * @return the given envelope
   */
  public EnvelopeND envelope(EnvelopeND envelope) {
    if (envelope == null)
      envelope = new EnvelopeND(this.getFactory());
    envelope.envelopeLite.set(this.envelopeLite);
    return envelope;
  }

  @Override
  public double getArea() {
    double volume = 1.0;
    for (int d = 0; d < envelopeLite.getCoordinateDimension(); d++)
      volume *= envelopeLite.getSideLength(d);
    return volume;
  }

  @Override
  public String getGeometryType() {
    return GeometryType.ENVELOPE.typename;
  }

  @Override
  public Coordinate getCoordinate() {
    return new CoordinateXY(this.envelopeLite.getMinCoord(0), this.envelopeLite.getMinCoord(1));
  }

  @Override
  public Coordinate[] getCoordinates() {
    Coordinate[] coordinates = new Coordinate[5];
    coordinates[0] = new CoordinateXY(this.envelopeLite.getMinCoord(0), this.envelopeLite.getMinCoord(1));
    coordinates[1] = new CoordinateXY(this.envelopeLite.getMaxCoord(0), this.envelopeLite.getMinCoord(1));
    coordinates[2] = new CoordinateXY(this.envelopeLite.getMaxCoord(0), this.envelopeLite.getMaxCoord(1));
    coordinates[3] = new CoordinateXY(this.envelopeLite.getMinCoord(0), this.envelopeLite.getMaxCoord(1));
    coordinates[4] = coordinates[0];
    return coordinates;
  }

  @Override
  public String toText() {
    return toWKT(new StringBuilder()).toString();
  }

  @Override
  protected Geometry reverseInternal() {
    return this;
  }

  @Override
  public boolean equalsExact(Geometry other, double tolerance) {
    EnvelopeND another = other instanceof EnvelopeND? (EnvelopeND) other :
        new EnvelopeND(this.factory).merge(other);
    if (this.getCoordinateDimension() != another.getCoordinateDimension())
      return false;
    for (int $d = 0; $d < this.getCoordinateDimension(); $d++) {
      if (Math.abs(this.getMinCoord($d) - another.getMinCoord($d)) > tolerance)
        return false;
      if (Math.abs(this.getMaxCoord($d) - another.getMaxCoord($d)) > tolerance)
        return false;
    }
    return true;
  }

  @Override
  public void apply(CoordinateFilter filter) {
    throw new RuntimeException("Not yet implemented");
  }

  @Override
  public void apply(CoordinateSequenceFilter filter) {
    throw new RuntimeException("Not yet implemented");
  }

  @Override
  public void apply(GeometryFilter filter) {
    throw new RuntimeException("Not yet implemented");
  }

  @Override
  public void apply(GeometryComponentFilter filter) {
    throw new RuntimeException("Not yet implemented");
  }

  @Override
  protected Geometry copyInternal() {
    return new EnvelopeND(this);
  }

  @Override
  public void normalize() {

  }

  @Override
  protected Envelope computeEnvelopeInternal() {
    return new Envelope(this.getMinCoord(0), this.getMaxCoord(0), this.getMinCoord(1), this.getMaxCoord(1));
  }

  @Override
  protected int compareToSameClass(Object o) {
    throw new RuntimeException("Not yet implemented");
  }

  @Override
  protected int compareToSameClass(Object o, CoordinateSequenceComparator comp) {
    throw new RuntimeException("Not yet implemented");
  }

  @Override
  protected int getTypeCode() {
    return 5; // Geometry.SORTINDEX_POLYGON
  }

  public void setEmpty() {
    this.envelopeLite.setEmpty();
    this.envelope = null;
  }

  public void shrink(EnvelopeNDLite that) {
    envelopeLite.shrink(that);
  }

  public void buffer(double... delta) {
    envelopeLite.buffer(delta);
  }

  public boolean containsEnvelope(EnvelopeNDLite other) {
    return envelopeLite.containsEnvelope(other);
  }

  public boolean containsEnvelope(Envelope other) {
    return envelopeLite.containsEnvelope(other);
  }

  public boolean isFinite() {
    return envelopeLite.isFinite();
  }

  public boolean equalsExact(EnvelopeNDLite other) {
    return envelopeLite.equalsExact(other);
  }

  public StringBuilder toWKT(StringBuilder out) {
    return this.envelopeLite.toWKT(out);
  }

  @Override
  public org.locationtech.jts.geom.Point getCentroid() {
    return factory.createPoint(new Coordinate(this.getCenter(0), this.getCenter(1)));
  }

  @Override
  public int getDimension() {
    return 2;
  }

  @Override
  public Geometry getBoundary() {
    throw new RuntimeException("Not yet implemented");
  }

  @Override
  public int getBoundaryDimension() {
    return 1;
  }

  @Override
  public String toString() {
    return envelopeLite.toString();
  }

  @Override
  public boolean isRectangle() {
    // While it makes sense to uncomment the next line, it will cause the internal functionality of JTS to break
    // since it will try to cast this object to Polygon while it is not a subclass of Polygon.
    //return getCoordinateDimension() == 2;
    return false;
  }

  // Override Geometry functions to work with n-dimensional envelopes


  @Override
  public IntersectionMatrix relate(Geometry g) {
    if (g instanceof EnvelopeND) {
      EnvelopeND other = (EnvelopeND) g;
      int dimensionResult = Math.min(this.getCoordinateDimension(), other.getCoordinateDimension());

      double[] minIntersection = new double[dimensionResult];
      double[] maxIntersection = new double[dimensionResult];
      int[] intersectionDimension = new int[dimensionResult];
      int minIntersectionDimension = 2;
      int maxIntersectionDimension = -1;
      boolean aCoversB = true;
      boolean bCoversA = true;
      boolean coincidentEdge = false;
      boolean aIsInfinite = true;
      boolean bIsInfinite = true;
      for (int $d = 0; $d < dimensionResult; $d++) {
        minIntersection[$d] = Math.max(this.getMinCoord($d), other.getMinCoord($d));
        maxIntersection[$d] = Math.min(this.getMaxCoord($d), other.getMaxCoord($d));
        if (minIntersection[$d] < maxIntersection[$d])
          intersectionDimension[$d] = Dimension.L; // Intersection is a line in this dimension
        else if (minIntersection[$d] == maxIntersection[$d])
          intersectionDimension[$d] = Dimension.P; // Intersection is a point in this dimension
        else /*if (minIntersection[$d] > maxIntersection[$d])*/
          intersectionDimension[$d] = Dimension.FALSE; // Disjoint in this dimension
        minIntersectionDimension = Math.min(minIntersectionDimension, intersectionDimension[$d]);
        maxIntersectionDimension = Math.max(maxIntersectionDimension, intersectionDimension[$d]);
        bCoversA = bCoversA && minIntersection[$d] == this.getMinCoord($d) && maxIntersection[$d] == this.getMaxCoord($d);
        aCoversB = aCoversB && minIntersection[$d] == other.getMinCoord($d) && maxIntersection[$d] == other.getMaxCoord($d);
        coincidentEdge = coincidentEdge || this.getMinCoord($d) == other.getMinCoord($d);
        coincidentEdge = coincidentEdge || this.getMaxCoord($d) == other.getMaxCoord($d);
        aIsInfinite = aIsInfinite && this.getMinCoord($d) == Double.NEGATIVE_INFINITY
                && this.getMaxCoord($d) == Double.POSITIVE_INFINITY;
        bIsInfinite = bIsInfinite && other.getMinCoord($d) == Double.NEGATIVE_INFINITY
                && other.getMaxCoord($d) == Double.POSITIVE_INFINITY;
      }
      IntersectionMatrix m = new IntersectionMatrix();
      // Interior of A
      m.set(Location.INTERIOR, Location.INTERIOR, minIntersectionDimension == Dimension.L? Dimension.A : Dimension.FALSE);
      m.set(Location.INTERIOR, Location.BOUNDARY, (minIntersectionDimension == Dimension.L && // The intersection must be an area
              (!bCoversA || coincidentEdge))? // B cannot cover A unless there is at least one coincident dimension
                      Dimension.L :
                      Dimension.FALSE);
      m.set(Location.INTERIOR, Location.EXTERIOR, !bCoversA? Dimension.A : Dimension.FALSE);

      // Boundary of A
      m.set(Location.BOUNDARY, Location.INTERIOR, (minIntersectionDimension == Dimension.A && // The intersection must be an area
              (!aCoversB || coincidentEdge))? // A cannot cover B unless there is at least one coincident dimension
              Dimension.L :
              Dimension.FALSE);
      // Boundary X Boundary can be a line, a point, or none
      if (minIntersectionDimension == Dimension.L && !coincidentEdge)
        m.set(Location.BOUNDARY, Location.BOUNDARY, Dimension.P);
      else if (minIntersectionDimension == Dimension.L /*&& coincidentEdge*/)
        m.set(Location.BOUNDARY, Location.BOUNDARY, Dimension.L);
      else if (minIntersectionDimension == Dimension.P)
        m.set(Location.BOUNDARY, Location.BOUNDARY, Dimension.P);
      else /*if (minIntersectionDimension == Dimension.FALSE)*/
        m.set(Location.BOUNDARY, Location.BOUNDARY, Dimension.FALSE);
      // Boundary X Exterior can be a line or none
      m.set(Location.BOUNDARY, Location.EXTERIOR, bCoversA? Dimension.FALSE : Dimension.L);

      // Exterior of A
      m.set(Location.EXTERIOR, Location.INTERIOR, !aCoversB? Dimension.A : Dimension.FALSE);
      m.set(Location.EXTERIOR, Location.BOUNDARY, aCoversB? Dimension.FALSE : Dimension.L);

      // Exterior X Exterior can be area or none
      if (aIsInfinite || bIsInfinite)
        m.set(Location.EXTERIOR, Location.EXTERIOR, Dimension.FALSE);
      else
        m.set(Location.EXTERIOR, Location.EXTERIOR, Dimension.A);

      return m;
    }
    return super.relate(g);
  }

  public boolean isEmpty() {
    if (getCoordinateDimension() == 0)
      return true;
    for (int d = 0; d < getCoordinateDimension(); d++)
      if (getMaxCoord(d) < getMinCoord(d) || Double.isNaN(getMinCoord(d)) || Double.isNaN(getMaxCoord(d)))
        return true;
    return false;
  }

  public int getCoordinateDimension() {
    return envelopeLite.getCoordinateDimension();
  }

  public double getMinCoord(int d) {
    return envelopeLite.getMinCoord(d);
  }

  public void setMinCoord(int d, double x) {
    envelopeLite.setMinCoord(d, x);
    this.envelope = null;
  }

  public double getMaxCoord(int d) {
    return envelopeLite.getMaxCoord(d);
  }

  public void setMaxCoord(int d, double x) {
    envelopeLite.setMaxCoord(d, x);
    this.envelope = null;
  }

  public void set(EnvelopeND other) {
    envelopeLite.set(other.envelopeLite);
    this.envelope = null;
  }

  public void set(PointND p) {
    envelopeLite.set(p);
    this.envelope = null;
  }

  public void set(Coordinate c) {
    envelopeLite.set(c);
    this.envelope = null;
  }

  public void setInfinite() {
    envelopeLite.setInfinite();
    this.envelope = null;
  }

  public double getSideLength(int d) {
    return envelopeLite.getSideLength(d);
  }

  public double getCenter(int d) {
    return envelopeLite.getCenter(d);
  }

  public EnvelopeND merge(double[] point) {
    return new EnvelopeND(this.getFactory(), envelopeLite.merge(point));
  }

  public EnvelopeND merge(Geometry geom) {
    return new EnvelopeND(this.getFactory(), envelopeLite.merge(geom));
  }

  public void merge(EnvelopeND other) {
    envelopeLite.merge(other.envelopeLite);
  }

  public void merge(CoordinateSequence cs) {
    envelopeLite.merge(cs);
  }

  public void set(double[] minCoords, double[] maxCoords) {
    envelopeLite.set(minCoords, maxCoords);
    this.envelope = null;
  }

  public boolean overlaps(double[] min, double[] max) {
    return envelopeLite.overlaps(min, max);
  }

  public boolean intersectsEnvelope(EnvelopeNDLite envelope2) {
    return envelopeLite.intersectsEnvelope(envelope2);
  }

  public boolean containsPoint(double[] coord) {
    return envelopeLite.containsPoint(coord);
  }

  public boolean containsPoint(Coordinate c) {
    return envelopeLite.containsPoint(c);
  }

  public boolean containsPoint(PointND p) {
    return envelopeLite.containsPoint(p);
  }


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy