@Override
  @SuppressWarnings("unchecked")
  public String isValid() {

    String superIsValid = super.isValid();
    if (superIsValid != null) return superIsValid;

    if (intervals.isEmpty()) {
      return "No intervals specified";
    }

    for (int i = 1; i < intervals.size(); i++) {
      Interval<T> interval1 = intervals.get(i - 1);
      Interval<T> interval2 = intervals.get(i);

      if (!interval1.getMax().equals(interval2.getMin())) {
        return "Gap between " + interval1 + " and " + interval2;
      }

      if (interval1.getMin().equals(interval2.getMin())
          && interval1.getMax().equals(interval2.getMax())) {
        return "Repeating intervals " + interval1 + " and " + interval2;
      }
    }

    DataTypeWithRatioScale<T> type = (DataTypeWithRatioScale<T>) getDataType();
    if (lowerRange.getRepeatBound() != null
        && upperRange.getRepeatBound() != null
        && type.compare(lowerRange.getRepeatBound(), upperRange.getRepeatBound()) > 0) {
      return "Lower repeat bound must be < upper repeat bound";
    }

    if (lowerRange.getSnapBound() != null
        && lowerRange.getRepeatBound() != null
        && type.compare(lowerRange.getSnapBound(), lowerRange.getRepeatBound()) > 0) {
      return "Lower snap bound must be <= lower repeat bound";
    }

    if (lowerRange.getLabelBound() != null
        && lowerRange.getSnapBound() != null
        && type.compare(lowerRange.getLabelBound(), lowerRange.getSnapBound()) > 0) {
      return "Lower label bound must be <= lower snap bound";
    }

    if (upperRange.getRepeatBound() != null
        && upperRange.getSnapBound() != null
        && type.compare(upperRange.getSnapBound(), upperRange.getRepeatBound()) < 0) {
      return "Upper snap bound must be >= upper repeat bound";
    }

    if (lowerRange.getLabelBound() != null
        && upperRange.getSnapBound() != null
        && type.compare(upperRange.getLabelBound(), upperRange.getSnapBound()) < 0) {
      return "Upper label bound must be >= upper snap bound";
    }

    return null;
  }
예제 #2
0
 /**
  * Add a type to the slice at a given position, possibly changing the endpoints of some descendant
  * intervals.
  *
  * @param type the type to add to the slice
  * @param position a type already in the slice before which the new type will be placed, <code>
  *     null</code> if the type should be placed at the end of the slice
  * @param ancestors the new type's ancestors
  * @return the event for the endpoint changes, though there might be none
  */
 protected EndpointsChangedEvent add(Constant type, Constant position, Set<Constant> ancestors) {
   EndpointsChangedEvent event = new EndpointsChangedEvent(this, type);
   order.add(type, position);
   int typeLambda = lambdas.get(position), positionLambda = typeLambda;
   Set<Constant> reducedAncestors = new HashSet<Constant>(ancestors);
   for (Map.Entry<Constant, Interval<Constant>> entry : descendentIntervals.entrySet()) {
     Interval<Constant> value = entry.getValue();
     if (reducedAncestors.remove(entry.getKey())) {
       if (value.getMin() == position) {
         ++positionLambda;
         value.setMin(type);
         event.addMinChange(entry.getKey());
       }
       if (value.getMax() == position) {
         ++typeLambda;
       }
     } else if (value.getMax() == position) {
       value.setMax(type);
       event.addMaxChange(entry.getKey());
     }
   }
   descendentIntervals.put(type, new Interval<Constant>(order, type, position));
   for (Constant ancestor : reducedAncestors) {
     descendentIntervals.put(ancestor, new Interval<Constant>(order, type, position));
   }
   lambdas.put(type, typeLambda);
   lambdas.put(position, positionLambda);
   return event;
 }
예제 #3
0
 /**
  * Attempt to add a type to the slice, possibly changing the endpoints of some descendant
  * intervals.
  *
  * @param type the type to add to the slice
  * @param ancestors the new type's ancestors
  * @return if the addition was successful, the event for the endpoint changes, though there might
  *     be none; if the addition failed, <code>null</code>
  */
 public EndpointsChangedEvent add(Constant type, Set<Constant> ancestors) {
   Interval<Constant> common = asInterval();
   for (Constant ancestor : ancestors) {
     Interval<Constant> mask = descendentIntervals.get(ancestor);
     if (mask != null) {
       common.intersect(mask);
     }
   }
   // empty is okay, as long as we still have location
   if (order.compare(common.getMin(), common.getMax()) > 0) {
     return null;
   }
   int surroundMin = 0, surroundMax = 0;
   for (Constant ancestor : ancestors) {
     Interval<Constant> range = descendentIntervals.get(ancestor);
     if (range != null) {
       if (order.compare(range.getMin(), common.getMin()) < 0
           && order.compare(range.getMax(), common.getMin()) > 0) {
         ++surroundMin;
       }
       if (order.compare(range.getMin(), common.getMax()) < 0
           && order.compare(range.getMax(), common.getMax()) > 0) {
         ++surroundMax;
       }
     }
   }
   if (lambdas.get(common.getMin()) == surroundMin) {
     return add(type, common.getMin(), ancestors);
   }
   if (lambdas.get(common.getMax()) == surroundMax) {
     return add(type, common.getMax(), ancestors);
   }
   //// fast slicing: don't check between min and max
   return null;
 }