/**
   * Tests whether this PreparedPolygon intersects a given geometry.
   *
   * @param geom the test geometry
   * @return true if the test geometry intersects
   */
  public boolean intersects(Geometry geom) {
    /**
     * Do point-in-poly tests first, since they are cheaper and may result in a quick positive
     * result.
     *
     * <p>If a point of any test components lie in target, result is true
     */
    boolean isInPrepGeomArea = isAnyTestComponentInTarget(geom);
    if (isInPrepGeomArea) return true;

    /** If any segments intersect, result is true */
    List lineSegStr = SegmentStringUtil.extractSegmentStrings(geom);
    // only request intersection finder if there are segments (ie NOT for point inputs)
    if (lineSegStr.size() > 0) {
      boolean segsIntersect = prepPoly.getIntersectionFinder().intersects(lineSegStr);
      if (segsIntersect) return true;
    }

    /**
     * If the test has dimension = 2 as well, it is necessary to test for proper inclusion of the
     * target. Since no segments intersect, it is sufficient to test representative points.
     */
    if (geom.getDimension() == 2) {
      // TODO: generalize this to handle GeometryCollections
      boolean isPrepGeomInArea =
          isAnyTargetComponentInAreaTest(geom, prepPoly.getRepresentativePoints());
      if (isPrepGeomInArea) return true;
    }

    return false;
  }
  /**
   * Tests whether this geometry intersects a given geometry.
   *
   * @param geom the test geometry
   * @return true if the test geometry intersects
   */
  public boolean intersects(Geometry geom) {
    /** If any segments intersect, obviously intersects = true */
    List lineSegStr = SegmentStringUtil.extractSegmentStrings(geom);
    boolean segsIntersect = prepLine.getIntersectionFinder().intersects(lineSegStr);
    // MD - performance testing
    //		boolean segsIntersect = false;
    if (segsIntersect) return true;

    /** For L/L case we are done */
    if (geom.getDimension() == 1) return false;

    /** For L/A case, need to check for proper inclusion of the target in the test */
    if (geom.getDimension() == 2 && prepLine.isAnyTargetComponentInTest(geom)) return true;

    /** For L/P case, need to check if any points lie on line(s) */
    if (geom.getDimension() == 0) return isAnyTestPointInTarget(geom);

    //		return prepLine.getGeometry().intersects(geom);
    return false;
  }
  /**
   * Evaluate the <tt>contains</tt> or <tt>covers</tt> relationship for the given geometry.
   *
   * @param geom the test geometry
   * @return true if the test geometry is contained
   */
  protected boolean eval(Geometry geom) {
    /**
     * Do point-in-poly tests first, since they are cheaper and may result in a quick negative
     * result.
     *
     * <p>If a point of any test components does not lie in target, result is false
     */
    boolean isAllInTargetArea = isAllTestComponentsInTarget(geom);
    if (!isAllInTargetArea) return false;

    /**
     * If the test geometry consists of only Points, then it is now sufficient to test if any of
     * those points lie in the interior of the target geometry. If so, the test is contained. If
     * not, all points are on the boundary of the area, which implies not contained.
     */
    if (requireSomePointInInterior && geom.getDimension() == 0) {
      boolean isAnyInTargetInterior = isAnyTestComponentInTargetInterior(geom);
      return isAnyInTargetInterior;
    }

    /**
     * Check if there is any intersection between the line segments in target and test. In some
     * important cases, finding a proper interesection implies that the test geometry is NOT
     * contained. These cases are:
     *
     * <ul>
     *   <li>If the test geometry is polygonal
     *   <li>If the target geometry is a single polygon with no holes
     *       <ul>
     *         In both of these cases, a proper intersection implies that there is some portion of
     *         the interior of the test geometry lying outside the target, which means that the test
     *         is not contained.
     */
    boolean properIntersectionImpliesNotContained =
        isProperIntersectionImpliesNotContainedSituation(geom);
    // MD - testing only
    //		properIntersectionImpliesNotContained = true;

    // find all intersection types which exist
    findAndClassifyIntersections(geom);

    if (properIntersectionImpliesNotContained && hasProperIntersection) return false;

    /**
     * If all intersections are proper (i.e. no non-proper intersections occur) we can conclude that
     * the test geometry is not contained in the target area, by the Epsilon-Neighbourhood Exterior
     * Intersection condition. In real-world data this is likely to be by far the most common
     * situation, since natural data is unlikely to have many exact vertex segment intersections.
     * Thus this check is very worthwhile, since it avoid having to perform a full topological
     * check.
     *
     * <p>(If non-proper (vertex) intersections ARE found, this may indicate a situation where two
     * shells touch at a single vertex, which admits the case where a line could cross between the
     * shells and still be wholely contained in them.
     */
    if (hasSegmentIntersection && !hasNonProperIntersection) return false;

    /**
     * If there is a segment intersection and the situation is not one of the ones above, the only
     * choice is to compute the full topological relationship. This is because contains/covers is
     * very sensitive to the situation along the boundary of the target.
     */
    if (hasSegmentIntersection) {
      return fullTopologicalPredicate(geom);
      //			System.out.println(geom);
    }

    /**
     * This tests for the case where a ring of the target lies inside a test polygon - which implies
     * the exterior of the Target intersects the interior of the Test, and hence the result is false
     */
    if (geom instanceof Polygonal) {
      // TODO: generalize this to handle GeometryCollections
      boolean isTargetInTestArea =
          isAnyTargetComponentInAreaTest(geom, prepPoly.getRepresentativePoints());
      if (isTargetInTestArea) return false;
    }
    return true;
  }