package extractors.hog;

import Jama.Matrix;

/**
 * This class provides an implementation for the {@link GradientFieldGenerator}. It generates a gradient
 * field by computing the differences of gradients.
 * 
 */
public class DifferenceOfGradients implements GradientFieldGenerator {

	@Override
	public Gradient[][][] generateGradientField(double[][][] field) {
		Matrix[][][] gradientField = new Matrix[field.length - 2][field[0].length - 2][field[0][0].length - 2];
		// compute the simple gradients
		for (int x = 1; x < field.length - 1; x++) {
			for (int y = 1; y < field[x].length - 1; y++) {
				for (int z = 1; z < field[x][y].length - 1; z++) {
					Matrix m = new Matrix(3, 1);
					m.set(0, 0, field[x + 1][y][z] - field[x - 1][y][z]);
					m.set(1, 0, field[x][y + 1][z] - field[x][y - 1][z]);
					m.set(2, 0, field[x][y][z + 1] - field[x][y][z - 1]);
					gradientField[x - 1][y - 1][z - 1] = m;
				}
			}
		}
		// compute the differences
		Gradient[][][] diffOfGradients = new Gradient[gradientField.length - 2][gradientField[0].length - 2][gradientField[0][0].length - 2];
		for (int x = 1; x < gradientField.length - 1; x++) {
			for (int y = 1; y < gradientField[x].length - 1; y++) {
				for (int z = 1; z < gradientField[x][y].length - 1; z++) {
					double dx = gradientField[x + 1][y][z].minus(gradientField[x - 1][y][z]).norm2();
					double dy = gradientField[x][y + 1][z].minus(gradientField[x][y - 1][z]).norm2();
					double dz = gradientField[x][y][z + 1].minus(gradientField[x][y][z - 1]).norm2();
					diffOfGradients[x - 1][y - 1][z - 1] = new Gradient(dx, dy, dz);
				}
			}
		}
		return diffOfGradients;
	}

	@Override
	public int getResx(DistanceFieldGenerator dfg) {
		return dfg.getResx() - 4;
	}

	@Override
	public int getResy(DistanceFieldGenerator dfg) {
		return dfg.getResy() - 4;
	}

	@Override
	public int getResz(DistanceFieldGenerator dfg) {
		return dfg.getResz() - 4;
	}
}
