@Override
      public ContourAggregates<N> process(Aggregates<? extends N> aggregates, Renderer rend) {
        Single<N>[] ts = LocalUtils.stepTransfers(contourLevels, fill);
        Transfer.Specialized<N, N> t =
            new Fan.Specialized<>(new MergeContours<N>(aggregates.defaultValue()), ts, aggregates);

        return (ContourAggregates<N>) rend.transfer(aggregates, t);
      }
 @Override
 public MC_TYPE at(int x, int y, Aggregates<? extends Boolean> aggregates) {
   int code = 0;
   if (aggregates.get(x - 1, y - 1)) {
     code = code | DOWN_INDEX_LEFT;
   }
   if (aggregates.get(x, y - 1)) {
     code = code | DOWN_INDEX_RIGHT;
   }
   if (aggregates.get(x - 1, y)) {
     code = code | UP_INDEX_LEFT;
   }
   if (aggregates.get(x, y)) {
     code = code | UP_INDEX_RIGHT;
   }
   return MC_TYPE.get(code);
 }
 @Override
 public Boolean at(int x, int y, Aggregates<? extends N> aggregates) {
   Number v = aggregates.get(x, y);
   if (v == null) {
     return false;
   }
   double delta = threshold.doubleValue() - v.doubleValue();
   return delta < 0;
 }
    @Override
    public ContourAggregates<N> process(Aggregates<? extends N> aggregates, Renderer rend) {
      Aggregates<? extends N> padAggs = new PadAggregates<>(aggregates, null);

      Aggregates<Boolean> isoDivided = rend.transfer(padAggs, new ISOBelow<>(threshold));
      Aggregates<MC_TYPE> classified = rend.transfer(isoDivided, new MCClassifier());
      Shape s = Assembler.assembleContours(classified, isoDivided);
      GlyphList<Shape, N> contours = new GlyphList<>();

      contours.add(new SimpleGlyph<>(s, threshold));
      if (!fill) {
        isoDivided = rend.transfer(isoDivided, new General.Simplify<>(isoDivided.defaultValue()));
      }
      Aggregates<N> base =
          rend.transfer(
              isoDivided, new General.MapWrapper<>(true, threshold, aggregates.defaultValue()));
      return new ContourAggregates<>(base, contours);
    }
    /**
     * Build a single path from all of the contour parts.
     *
     * <p>May be disjoint and have holes (thus GeneralPath).
     *
     * @param classified The line-segment classifiers
     * @param isoDivided Original classification, used to disambiguate saddle conditions
     * @return Resulting contour
     */
    public static final GeneralPath assembleContours(
        Aggregates<MC_TYPE> classified, Aggregates<Boolean> isoDivided) {
      GeneralPath isoPath = new GeneralPath(GeneralPath.WIND_EVEN_ODD);

      // Find an unambiguous case of an actual line, follow it around and build the line.
      // Stitching sets the line segments that have been "consumed" to MC_TYPE.empty, so segments
      // are only processed once.
      for (int x = classified.lowX(); x < classified.highX(); x++) {
        for (int y = classified.lowY(); y < classified.highY(); y++) {
          MC_TYPE type = classified.get(x, y);
          if (type != MC_TYPE.empty
              && type != MC_TYPE.surround
              && type != MC_TYPE.diag_one
              && type != MC_TYPE.diag_two) {
            stichContour(classified, isoDivided, isoPath, x, y);
          }
        }
      }
      return isoPath;
    }
    /**
     * An iso level can be made of multiple regions with holes in them. This builds one path (into
     * the passed GeneralPath) that represents one connected contour.
     *
     * @param isoData Marching-cubes classification at each cell
     * @param isoDivided The boolean above/below classification for each cell (to disambiguate
     *     saddles)
     * @param iso The path to build into
     */
    public static void stichContour(
        Aggregates<MC_TYPE> isoData,
        Aggregates<Boolean> isoDivided,
        GeneralPath iso,
        int startX,
        int startY) {
      int x = startX, y = startY;

      SIDE prevSide = SIDE.NONE;

      // Found an unambiguous iso line at [r][c], so start there.
      MC_TYPE startCell = isoData.get(x, y);
      Point2D nextPoint = startCell.firstSide(prevSide).nextPoint(x, y);
      iso.moveTo(nextPoint.getX(), nextPoint.getY());
      prevSide = isoData.get(x, y).secondSide(prevSide, isoDivided.get(x, y));

      // System.out.printf("-------------------\n);

      do {
        // Process current cell
        MC_TYPE curCell = isoData.get(x, y);
        nextPoint = curCell.secondSide(prevSide, isoDivided.get(x, y)).nextPoint(x, y);
        // System.out.printf("%d,%d: %s\n",x,y,curCell.secondSide(prevSide, isoDivided.get(x,y)));
        iso.lineTo(nextPoint.getX(), nextPoint.getY());
        SIDE nextSide = curCell.secondSide(prevSide, isoDivided.get(x, y));
        isoData.set(x, y, curCell.clearWith()); // Erase this marching cube line entry

        // Advance for next cell
        prevSide = nextSide;
        switch (nextSide) {
          case LEFT:
            x -= 1;
            break;
          case RIGHT:
            x += 1;
            break;
          case BOTTOM:
            y += 1;
            break;
          case TOP:
            y -= 1;
            break;
          case NONE:
            throw new IllegalArgumentException(
                "Encountered side NONE after starting contour line.");
        }

      } while (x != startX || y != startY);
      iso.closePath();
    }
 @Override
 public int highY() {
   return base.highY();
 }
 @Override
 public int lowY() {
   return base.lowY();
 }
 @Override
 public A defaultValue() {
   return base.defaultValue();
 }
Example #10
0
 @Override
 public void set(int x, int y, A val) {
   base.set(x, y, val);
 }
Example #11
0
 @Override
 public A get(int x, int y) {
   return base.get(x, y);
 }
Example #12
0
 @Override
 public Iterator<A> iterator() {
   return base.iterator();
 }
Example #13
0
 public int highY() {
   return base.highY() + 1;
 }
Example #14
0
 public int lowY() {
   return base.lowY() - 1;
 }
Example #15
0
 public A defaultValue() {
   return base.defaultValue();
 }
Example #16
0
 @Override
 public A get(int x, int y) {
   if ((x >= base.lowX() && x < base.highX()) && (y >= base.lowY() && y < base.highY())) {
     return base.get(x, y); // Its inside
   } else if ((x == base.lowX() - 1 || x == base.highX() + 1)
       && (y >= base.lowY() - 1 && y < base.highY() + 1)) {
     return pad; // Its immediate above or below
   } else if ((y == base.lowY() - 1 || y == base.highY() + 1)
       && (x >= base.lowX() - 1 && x < base.highX() + 1)) {
     return pad; // Its immediately left or right
   } else {
     return base.defaultValue();
   }
 }