code: /*******************************************************************************
   * Copyright (c) 2015 Voyager Search and MITRE
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of the Apache License, Version 2.0 which
   * accompanies this distribution and is available at
   *    http://www.apache.org/licenses/LICENSE-2.0.txt
   ******************************************************************************/
  
  package org.locationtech.spatial4j.shape;
  
  /**
   * The set of spatial relationships.  Naming is somewhat consistent with OGC spec
   * conventions as seen in SQL/MM and others.
   * <p>
   * There is no equality case.  If two Shape instances are equal then the result
   * might be CONTAINS (preferred) or WITHIN.  Client logic may have to be aware
   * of this edge condition; Spatial4j testing certainly does.
   * <p>
   * The "CONTAINS" and "WITHIN" wording here is inconsistent with OGC; these here map to OGC
   * "COVERS" and "COVERED BY", respectively. The distinction is in the boundaries; in Spatial4j
   * there is no boundary distinction -- boundaries are part of the shape as if it was an "interior",
   * with respect to OGC's terminology.
   */
  public enum SpatialRelation {
    //see http://docs.geotools.org/latest/userguide/library/jts/dim9.html#preparedgeometry
  
    /**
     * The shape is within the target geometry. It's the converse of {@link #CONTAINS}.
     * Boundaries of shapes count too.  OGC specs refer to this relation as "COVERED BY";
     * WITHIN is differentiated there by not including boundaries.
     */
    WITHIN,
  
    /**
     * The shape contains the target geometry. It's the converse of {@link #WITHIN}.
     * Boundaries of shapes count too.  OGC specs refer to this relation as "COVERS";
     * CONTAINS is differentiated there by not including boundaries.
     */
    CONTAINS,
  
    /**
     * The shape shares no point in common with the target shape.
     */
    DISJOINT,
  
    /**
     * The shape shares some points/overlap with the target shape, and the relation is
     * not more specifically {@link #WITHIN} or {@link #CONTAINS}.
     */
    INTERSECTS;
    //Don't have these: TOUCHES, CROSSES, OVERLAPS, nor distinction between CONTAINS/COVERS
  
    /**
     * Given the result of <code>shapeA.relate(shapeB)</code>, transposing that
     * result should yield the result of <code>shapeB.relate(shapeA)</code>. There
     * is a corner case is when the shapes are equal, in which case actually
     * flipping the relate() call will result in the same value -- either CONTAINS
     * or WITHIN; this method can't possible check for that so the caller might
     * have to.
     */
    public SpatialRelation transpose() {
      switch(this) {
        case CONTAINS: return SpatialRelation.WITHIN;
        case WITHIN: return SpatialRelation.CONTAINS;
        default: return this;
      }
    }
  
    /**
     * If you were to call aShape.relate(bShape) and aShape.relate(cShape), you
     * could call this to merge the intersect results as if bShape &amp; cShape were
     * combined into {@link ShapeCollection}.  If {@code other} is null then the
     * result is "this".
     */
    public SpatialRelation combine(SpatialRelation other) {
      // You can think of this algorithm as a state transition / automata.
      // 1. The answer must be the same no matter what the order is.
      // 2. If any INTERSECTS, then the result is INTERSECTS (done).
      // 3. A DISJOINT + WITHIN == INTERSECTS (done).
      // 4. A DISJOINT + CONTAINS == CONTAINS.
      // 5. A CONTAINS + WITHIN == INTERSECTS (done). (weird scenario)
      // 6. X + X == X.)
      // 7. X + null == X;
      if (other == this || other == null)
        return this;
      if (this == DISJOINT && other == CONTAINS
          || this == CONTAINS && other == DISJOINT)
        return CONTAINS;
      return INTERSECTS;
    }
  
    /** Not DISJOINT, i.e. there is some sort of intersection. */
    public boolean intersects() {
      return this != DISJOINT;
    }
  
    /**
     * If <code>aShape.relate(bShape)</code> is r, then <code>r.inverse()</code>
     * is <code> inverse(aShape).relate(bShape)</code> whereas
     * <code>inverse(shape)</code> is theoretically the opposite area covered by a
     * shape, i.e. everywhere but where the shape is.
     * <p>
     * Note that it's not commutative!  <code>WITHIN.inverse().inverse() !=
     * WITHIN</code>.
     */
    public SpatialRelation inverse() {
      switch(this) {
        case DISJOINT: return CONTAINS;
        case CONTAINS: return DISJOINT;
        case WITHIN: return INTERSECTS;//not commutative!
      }
      return INTERSECTS;
    }
  
  }
  