public SpatialRelation relate(SpanUnitsNRShape spanShape) {
   assertDecoded();
   int startCmp = comparePrefix(spanShape.getMinUnit(), this);
   if (startCmp > 0) { // start comes after this cell
     return SpatialRelation.DISJOINT;
   }
   int endCmp = comparePrefix(spanShape.getMaxUnit(), this);
   if (endCmp < 0) { // end comes before this cell
     return SpatialRelation.DISJOINT;
   }
   int nrMinLevel = spanShape.getMinUnit().getLevel();
   int nrMaxLevel = spanShape.getMaxUnit().getLevel();
   if ((startCmp < 0 || startCmp == 0 && nrMinLevel <= getLevel())
       && (endCmp > 0 || endCmp == 0 && nrMaxLevel <= getLevel()))
     return SpatialRelation.WITHIN; // or equals
   // At this point it's Contains or Within.
   if (startCmp != 0 || endCmp != 0) return SpatialRelation.INTERSECTS;
   // if min or max Level is less, it might be on the equivalent edge.
   for (; nrMinLevel < getLevel(); nrMinLevel++) {
     if (getValAtLevel(nrMinLevel + 1) != 0) return SpatialRelation.INTERSECTS;
   }
   for (; nrMaxLevel < getLevel(); nrMaxLevel++) {
     if (getValAtLevel(nrMaxLevel + 1) != getNumSubCells(getShapeAtLevel(nrMaxLevel)) - 1)
       return SpatialRelation.INTERSECTS;
   }
   return SpatialRelation.CONTAINS;
 }
 public SpatialRelation relate(SpanUnitsNRShape ext) {
   // This logic somewhat mirrors RectangleImpl.relate_range()
   int extMin_intMax = comparePrefix(ext.getMinUnit(), getMaxUnit());
   if (extMin_intMax > 0) return SpatialRelation.DISJOINT;
   int extMax_intMin = comparePrefix(ext.getMaxUnit(), getMinUnit());
   if (extMax_intMin < 0) return SpatialRelation.DISJOINT;
   int extMin_intMin = comparePrefix(ext.getMinUnit(), getMinUnit());
   int extMax_intMax = comparePrefix(ext.getMaxUnit(), getMaxUnit());
   if ((extMin_intMin > 0
           || extMin_intMin == 0 && ext.getMinUnit().getLevel() >= getMinUnit().getLevel())
       && (extMax_intMax < 0
           || extMax_intMax == 0 && ext.getMaxUnit().getLevel() >= getMaxUnit().getLevel()))
     return SpatialRelation.CONTAINS;
   if ((extMin_intMin < 0
           || extMin_intMin == 0 && ext.getMinUnit().getLevel() <= getMinUnit().getLevel())
       && (extMax_intMax > 0
           || extMax_intMax == 0 && ext.getMaxUnit().getLevel() <= getMaxUnit().getLevel()))
     return SpatialRelation.WITHIN;
   return SpatialRelation.INTERSECTS;
 }
    private void initIter(Shape filter) {
      cellNumber = -1;
      if (filter instanceof UnitNRShape && ((UnitNRShape) filter).getLevel() == 0)
        filter = null; // world means everything -- no filter
      iterFilter = filter;

      NRCell parent = getShapeAtLevel(getLevel() - 1);

      // Initialize iter* members.

      // no filter means all subcells
      if (filter == null) {
        iterFirstCellNumber = 0;
        iterFirstIsIntersects = false;
        iterLastCellNumber = getNumSubCells(parent) - 1;
        iterLastIsIntersects = false;
        return;
      }

      final UnitNRShape minLV;
      final UnitNRShape maxLV;
      final int lastLevelInCommon; // between minLV & maxLV
      if (filter instanceof SpanUnitsNRShape) {
        SpanUnitsNRShape spanShape = (SpanUnitsNRShape) iterFilter;
        minLV = spanShape.getMinUnit();
        maxLV = spanShape.getMaxUnit();
        lastLevelInCommon = spanShape.getLevelsInCommon();
      } else {
        minLV = (UnitNRShape) iterFilter;
        maxLV = minLV;
        lastLevelInCommon = minLV.getLevel();
      }

      // fast path optimization that is usually true, but never first level
      if (iterFilter == parent.iterFilter
          && (getLevel() <= lastLevelInCommon
              || parent.iterFirstCellNumber != parent.iterLastCellNumber)) {
        // TODO benchmark if this optimization pays off. We avoid two comparePrefixLV calls.
        if (parent.iterFirstIsIntersects
            && parent.cellNumber == parent.iterFirstCellNumber
            && minLV.getLevel() >= getLevel()) {
          iterFirstCellNumber = minLV.getValAtLevel(getLevel());
          iterFirstIsIntersects = (minLV.getLevel() > getLevel());
        } else {
          iterFirstCellNumber = 0;
          iterFirstIsIntersects = false;
        }
        if (parent.iterLastIsIntersects
            && parent.cellNumber == parent.iterLastCellNumber
            && maxLV.getLevel() >= getLevel()) {
          iterLastCellNumber = maxLV.getValAtLevel(getLevel());
          iterLastIsIntersects = (maxLV.getLevel() > getLevel());
        } else {
          iterLastCellNumber = getNumSubCells(parent) - 1;
          iterLastIsIntersects = false;
        }
        if (iterFirstCellNumber == iterLastCellNumber) {
          if (iterLastIsIntersects) iterFirstIsIntersects = true;
          else if (iterFirstIsIntersects) iterLastIsIntersects = true;
        }
        return;
      }

      // not common to get here, except for level 1 which always happens

      int startCmp = comparePrefix(minLV, parent);
      if (startCmp > 0) { // start comes after this cell
        iterFirstCellNumber = 0;
        iterFirstIsIntersects = false;
        iterLastCellNumber = -1; // so ends early (no cells)
        iterLastIsIntersects = false;
        return;
      }
      int endCmp = comparePrefix(maxLV, parent); // compare to end cell
      if (endCmp < 0) { // end comes before this cell
        iterFirstCellNumber = 0;
        iterFirstIsIntersects = false;
        iterLastCellNumber = -1; // so ends early (no cells)
        iterLastIsIntersects = false;
        return;
      }
      if (startCmp < 0 || minLV.getLevel() < getLevel()) {
        // start comes before...
        iterFirstCellNumber = 0;
        iterFirstIsIntersects = false;
      } else {
        iterFirstCellNumber = minLV.getValAtLevel(getLevel());
        iterFirstIsIntersects = (minLV.getLevel() > getLevel());
      }
      if (endCmp > 0 || maxLV.getLevel() < getLevel()) {
        // end comes after...
        iterLastCellNumber = getNumSubCells(parent) - 1;
        iterLastIsIntersects = false;
      } else {
        iterLastCellNumber = maxLV.getValAtLevel(getLevel());
        iterLastIsIntersects = (maxLV.getLevel() > getLevel());
      }
      if (iterFirstCellNumber == iterLastCellNumber) {
        if (iterLastIsIntersects) iterFirstIsIntersects = true;
        else if (iterFirstIsIntersects) iterLastIsIntersects = true;
      }
    }