public int getPixel(int x, int y, int[] inPixels, int width, int height) {
    float nx = m00 * x + m01 * y;
    float ny = m10 * x + m11 * y;
    nx /= scale;
    ny /= scale * stretch;
    nx += 1000;
    ny += 1000; // Reduce artifacts around 0,0
    float f = evaluate(nx, ny);

    float f1 = results[0].distance;
    float f2 = results[1].distance;
    int srcx = ImageMath.clamp((int) ((results[0].x - 1000) * scale), 0, width - 1);
    int srcy = ImageMath.clamp((int) ((results[0].y - 1000) * scale), 0, height - 1);
    int v = inPixels[srcy * width + srcx];
    f = (f2 - f1) / edgeThickness;
    f = ImageMath.smoothStep(0, edgeThickness, f);
    if (fadeEdges) {
      srcx = ImageMath.clamp((int) ((results[1].x - 1000) * scale), 0, width - 1);
      srcy = ImageMath.clamp((int) ((results[1].y - 1000) * scale), 0, height - 1);
      int v2 = inPixels[srcy * width + srcx];
      v2 = ImageMath.mixColors(0.5f, v2, v);
      v = ImageMath.mixColors(f, v2, v);
    } else v = ImageMath.mixColors(f, edgeColor, v);
    return v;
  }
  protected BufferedImage filterPixelsNN(
      BufferedImage dst, int width, int height, int[] inPixels, Rectangle transformedSpace) {
    int srcWidth = width;
    int srcHeight = height;
    int outWidth = transformedSpace.width;
    int outHeight = transformedSpace.height;
    int outX, outY, srcX, srcY;
    int[] outPixels = new int[outWidth];

    outX = transformedSpace.x;
    outY = transformedSpace.y;
    int[] rgb = new int[4];
    float[] out = new float[2];

    for (int y = 0; y < outHeight; y++) {
      for (int x = 0; x < outWidth; x++) {
        transformInverse(outX + x, outY + y, out);
        srcX = (int) out[0];
        srcY = (int) out[1];
        // int casting rounds towards zero, so we check out[0] < 0, not srcX < 0
        if (out[0] < 0 || srcX >= srcWidth || out[1] < 0 || srcY >= srcHeight) {
          int p;
          switch (edgeAction) {
            case ZERO:
            default:
              p = 0;
              break;
            case WRAP:
              p =
                  inPixels[
                      (ImageMath.mod(srcY, srcHeight) * srcWidth) + ImageMath.mod(srcX, srcWidth)];
              break;
            case CLAMP:
              p =
                  inPixels[
                      (ImageMath.clamp(srcY, 0, srcHeight - 1) * srcWidth)
                          + ImageMath.clamp(srcX, 0, srcWidth - 1)];
              break;
            case RGB_CLAMP:
              p =
                  inPixels[
                          (ImageMath.clamp(srcY, 0, srcHeight - 1) * srcWidth)
                              + ImageMath.clamp(srcX, 0, srcWidth - 1)]
                      & 0x00ffffff;
          }
          outPixels[x] = p;
        } else {
          int i = srcWidth * srcY + srcX;
          rgb[0] = inPixels[i];
          outPixels[x] = inPixels[i];
        }
      }
      setRGB(dst, 0, y, transformedSpace.width, 1, outPixels);
    }
    return dst;
  }
 private final int getPixel(int[] pixels, int x, int y, int width, int height) {
   if (x < 0 || x >= width || y < 0 || y >= height) {
     switch (edgeAction) {
       case ZERO:
       default:
         return 0;
       case WRAP:
         return pixels[(ImageMath.mod(y, height) * width) + ImageMath.mod(x, width)];
       case CLAMP:
         return pixels[
             (ImageMath.clamp(y, 0, height - 1) * width) + ImageMath.clamp(x, 0, width - 1)];
       case RGB_CLAMP:
         return pixels[
                 (ImageMath.clamp(y, 0, height - 1) * width) + ImageMath.clamp(x, 0, width - 1)]
             & 0x00ffffff;
     }
   }
   return pixels[y * width + x];
 }
 /**
  * Set a knot position.
  *
  * @param n the knot index
  * @param x the knot position
  * @see #setKnotPosition
  */
 public void setKnotPosition(int n, int x) {
   xKnots[n] = ImageMath.clamp(x, 0, 255);
   sortKnots();
   rebuildGradient();
 }