
	// Carve a rectangle (x0, y0) - (x1, y1) from the image map.
	// Return null in case this is not possible.
	// TODO: dead-code for now
	public ImageMap Carve (int x0, int y0, int x1, int y1)
	{
		if (x0 < 0 || x0 >= xDim || y0 < 0 || y0 >= yDim ||
			x1 < 0 || x1 >= xDim || y1 < 0 || y1 >= yDim ||
			x0 >= x1 || y0 >= y1)
		{
			return (null);
		}

		ImageMap cMap = new ImageMap (x1 - x0, y1 - y0);

		for (int y = 0 ; y < (y1 - y0) ; ++y)
			for (int x = 0 ; x < (x1 - x0) ; ++x)
				cMap[x, y] = this[x0 + x, y0 + y];

		return (cMap);
	}

	// Rotate 'steps' steps leftward in 90 degree steps.
	public ImageMap RotateQuadratic90 (int steps)
	{
		ImageMap res;

		// 180 or 270 degrees left
		if (steps >= 2) {
			res = new ImageMap (xDim, yDim);
			steps -= 2;

			for (int y = 0 ; y < yDim ; ++y)
				for (int x = 0 ; x < xDim ; ++x)
					res[x, y] = this[(xDim - 1) - x, (yDim - 1) - y];
		} else
			res = this;

		if (steps == 0)
			return (res);

		// one 90 degree step
		ImageMap rot = new ImageMap (xDim, yDim);
		for (int y = 0 ; y < yDim ; ++y)
			for (int x = 0 ; x < xDim ; ++x)
				rot[x, y] = res[(yDim - 1) - y, x];

		return (rot);
	}

	// Rotate a quadratic image map by an angle.
	//
	// Using a high quality sinc transform the image map is rotated around its
	// center pixel by 'angle' degrees, which lies in the range [-PI ; PI] or
	// [0 ; 2 PI], as you wish. Note: we rotate in the mathematically positive
	// rotation direction (> 0 leftward).
	//
	// Except for the trivial angle = 0.0 the rotation loses information from
	// the map. This loss can be estimated by
	//
	//   lowerBoundDim = dim / sqrt(2)
	//
	// For example: if the source image has 32 pixels in each dimension, only
	// the pixels within the circle area with the diameter of lowerBoundDim
	// pixels can be guaranteed to be valid after calling this function,
	// (32 / sqrt(2) = 22, so pi * 11^2 = 380 valid pixels).
	//
	// The exact details of the method were discovered in
	// http://bigwww.epfl.ch/publications/unser9502.html, and most steps are
	// modelled after this paper.
	//
	// Return the new image map.
	public ImageMap RotateCircleInQuadratic (double angle)
	{
		if (yDim != xDim ||
			angle <= (-2.0 * Math.PI) || angle >= (2.0 * Math.PI))
		{
			throw (new Exception ("cannot rotate rectangle, params at fault"));
		}

		if (angle == 0.0 || angle == 2.0 * Math.PI)
			return ((ImageMap) Clone ());

		if (angle < 0.0)
			angle += 2.0 * Math.PI;

		int d90rotations = (int) ((2.0 * angle) / Math.PI);
		angle = angle - (d90rotations * (Math.PI / 2.0));
		ImageMap rot = this;

		if (d90rotations > 0)
			rot = RotateQuadratic90 (d90rotations);

		// Three steps, where 1. & 3. are the same
		ImageMap shear1 = rot.RCShearX (angle);
		ImageMap shear2 = shear1.RCShearY (angle);
		ImageMap shearRes = shear2.RCShearX (angle);

		return (shearRes);
	}

	// 1. & 3. step: shearing by a given angle in X direction
	// FIXME: currently broken due to new convolution filter
	private ImageMap RCShearX (double angle)
	{
		ImageMap res = new ImageMap (xDim, yDim);
		double tanA2 = -Math.Tan (angle / 2.0);

		ConvLinearMask lineMask =
			new ConvLinearMask (2 * xDim);

		for (int y = 0 ; y < yDim ; ++y) {
			double shiftWidth = (y - (yDim / 2)) * tanA2;

			// fill mask
			for (int n = 0 ; n < (2 * xDim) ; ++n) {
				double relShift = (n - xDim) - shiftWidth;
				double weight = RCSinc (relShift) *
					RCSinc (relShift / (xDim / 2));

				lineMask[n] = weight;
			}

			for (int x = 0 ; x < xDim ; ++x) {
				double r = ConvolutionFilter.CalculateConvolutionValue1D (this,
					lineMask, y, x, yDim, xDim,
					ConvolutionFilter.Direction.Vertical);

				// very small negative r's can appear, get rid of them.
				if (r < 0.0)
					r = 0.0;
				res[x, y] = r;
			}
		}
		return (res);
	}

	// 2. step: shearing by a given angle in Y direction
	// FIXME: currently broken due to new convolution filter
	private ImageMap RCShearY (double angle)
	{
		double sinA = Math.Sin (angle);
		ImageMap res = new ImageMap (xDim, yDim);

		ConvLinearMask lineMask =
			new ConvLinearMask (2 * xDim);

		for (int x = 0 ; x < xDim ; ++x) {
			double shiftWidth = (x - (xDim / 2)) * sinA;

			// fill mask
			for (int n = 0 ; n < (2 * yDim) ; ++n) {
				double relShift = (n - yDim) - shiftWidth;
				double weight = RCSinc (relShift) *
					RCSinc (relShift / (yDim / 2));

				lineMask[n] = weight;
			}

			for (int y = 0 ; y < yDim ; ++y) {
				double r = ConvolutionFilter.CalculateConvolutionValue1D (this,
					lineMask, x, y, xDim, yDim,
					ConvolutionFilter.Direction.Horizontal);

				// very small negative r's can appear, get rid of them.
				if (r < 0.0)
					r = 0.0;
				res[x, y] = r;
			}
		}
		return (res);
	}

	private double RCSinc (double dist)
	{
		dist *= Math.PI;
		if (dist == 0.0)
			return (1.0);

		return (Math.Sin (dist) / dist);
	}

