@Override
    public HeightMap applyTo(HeightMap... heightMaps){
        double[][] finalHeights = heightMaps[0].getHeights();
        int xSize = finalHeights.length;
        int ySize = finalHeights[0].length;
        for(int iteration = 0; iteration<numIterations; iteration++) {
            if (iteration % 10 == 0) System.out.println("AverageFilter " + 100 * iteration / numIterations + "% complete");
            for (int x = 0; x < xSize; x++) {
                for (int y = 0; y < ySize; y++) {
                    //for non-reversed, move a quantity equal to (maxDifference-tAngle)/2
                    double heightDifference = maxDifference(
                            finalHeights[x][y],
                            finalHeights[(x+xSize-1)%xSize][(y+ySize-1)%ySize],
                            finalHeights[(x+xSize-1)%xSize][(y+1)%ySize],
                            finalHeights[(x+1)%xSize][(y+ySize-1)%ySize],
                            finalHeights[(x+1)%xSize][(y+1)%ySize]
                            );

                    //if the maximum difference is less than the talus angle,
                    //find the neighbor with the most difference and give it some of the center's soil
                    if(heightDifference>tAngle){
                        //System.out.println("\nHeight difference: "+heightDifference);
                        //System.out.println("Height before: "+finalHeights[x][y]);
                        if(abs(finalHeights[(x+xSize-1)%xSize][(y+ySize-1)%ySize] - finalHeights[x][y])  == heightDifference){
                            finalHeights[x][y] -= (heightDifference-tAngle)*solubility/2;
                            finalHeights[(x+xSize-1)%xSize][(y+ySize-1)%ySize]+=(heightDifference-tAngle)*solubility/2;
                        }
                        else if(abs(finalHeights[(x+xSize-1)%xSize][(y+ySize+1)%ySize] - finalHeights[x][y])  == heightDifference){
                            finalHeights[x][y] -= (heightDifference-tAngle)*solubility/2;
                            finalHeights[(x+xSize-1)%xSize][(y+1)%ySize]+=(heightDifference-tAngle)*solubility/2;
                        }
                        else if(abs(finalHeights[(x+xSize+1)%xSize][(y+ySize-1)%ySize] - finalHeights[x][y])  == heightDifference){
                            finalHeights[x][y] -= (heightDifference-tAngle)*solubility/2;
                            finalHeights[(x+1)%xSize][(y+ySize-1)%ySize]+=(heightDifference-tAngle)*solubility/2;
                        }
                        else if(abs(finalHeights[(x+xSize+1)%xSize][(y+ySize+1)%ySize] - finalHeights[x][y])  == heightDifference){
                            finalHeights[x][y] -= (heightDifference-tAngle)*solubility/2;
                            finalHeights[(x+1)%xSize][(y+1)%ySize]+=(heightDifference-tAngle)*solubility/2;
                        }
                        //System.out.println("Height after: "+finalHeights[x][y]);
                    }
                }
            }
        }
        return new HeightMap(finalHeights);
    }