/*--- formatted by Jindent 2.1, (www.c-lab.de/~jindent) ---*/

/*
 * JIGL--Java Imaging and Graphics Library
 * Copyright (C)1999 Brigham Young University
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 * A copy of the GNU Library General Public Licence is contained in
 * /jigl/licence.txt
 */

package jm.jigl; // Modifizierte Paketstruktur [JM]
import java.*;
import jm.jigl.*;

// import jigl.math.*;


/**
 * A complex signal is a set of two real gray signal planes.<P>
 * ComplexSignal implements Signal
 * @version 1.3, Modifikation der urspruenglichen jigl Paketstruktur durch Jens Martin
 * @see jigl.math.ComplexSignal
 */

public class ComplexSignal implements Signal {


	/**
	 * The Real plane of the signal
	 */
	protected RealSignal	real;


	/**
	 * The Imaginary part of the signal
	 */
	protected RealSignal	imag;


	/**
	 * Cartesian length of the signal
	 */
	protected int					length;

	/*
	 * constructors
	 */


	/**
	 * Creates a ComplexSignal with height and width of zero and the real and imaginary
	 * planes set to null
	 */
	public ComplexSignal() {
		length = 0;
		real = null;
		imag = null;
	}


	/**
	 * Creates a ComplexSignal with height and width of x and y repectively
	 */
	public ComplexSignal(int x) {
		length = x;
		real = new RealSignal(length);
		imag = new RealSignal(length);
	}


	/**
	 * Creates a ComplexSignal as a shallow copy of a complex signal
	 */
	public ComplexSignal(ComplexSignal s) {
		length = s.length();
		real = s.real();
		imag = s.imag();
	}



	/**
	 * Returns the length of the signal
	 * @param none
	 */
	public final int length() {
		return length;
	}


	/*
	 * copiers
	 */


	/**
	 * Makes a shallow copy of the real plane
	 */
	public final RealSignal real() {
		return real;
	}


	/**
	 * Makes a shallow copy of the imaginary plane
	 */
	public final RealSignal imag() {
		return imag;
	}


	/**
	 * Makes a deep copy of this signal
	 * @param none
	 * @return a deep copy of ComplexSignal
	 */
	public Signal copy() {
		ComplexSignal c = new ComplexSignal(length);

		for (int x = 0; x < length; x++) {
			c.real.set(x, real.get(x));
			c.imag.set(x, imag.get(x));
		}

		return c;
	}


	/**
	 * Set the real plane of this signal
	 * @param pl the RealSignal to set the real plane to
	 */
	public final void setReal(RealSignal pl) {
		real = pl;
	}


	/**
	 * Set the real plane of this signal
	 * @param pl the RealSignal to set the real plane to
	 */
	public final void setImag(RealSignal pl) {
		imag = pl;
	}


	/*
	 * buffer access
	 */


	/**
	 * Returns the pixel value at the given x value of the real plane
	 * @param x  the length coordinant
	 */
	public final float getReal(int x) {
		return real.get(x);
	}


	/**
	 * Returns the pixel value at the given x value of the imaginary plane
	 * @param x  the length coordinant
	 */
	public final float getImag(int x) {
		return imag.get(x);
	}


	/**
	 * Sets the pixel value at x to a given value of the real plane
	 * @param x the length coordinant
	 * @param v the value to set the pixel to
	 */
	public final void setReal(int x, float v) {
		real.set(x, v);
	}


	/**
	 * Sets the pixel value at x to a given value of the imaginary
	 * @param x the length coordinant
	 * @param v the value to set the pixel to
	 */
	public final void setImag(int x, float v) {
		imag.set(x, v);
	}


	/**
	 * Sets the pixel value at x to a given value of this signal
	 * @param x the length coordinant
	 *
	 * @param r the value to set the pixel to in the real plane
	 * @param i the value to set the pixel to in the imaginary plane
	 */
	public final void set(int x, float r, float i) {
		real.set(x, r);
		imag.set(x, i);
	}

	/*
	 * range functions
	 */


	/**
	 * Returns the minimum magnitude in this signal
	 * @param none
	 */
	public final Complex min() {
		Complex p = new Complex();
		Complex min = new Complex(Double.MAX_VALUE, Double.MAX_VALUE);


		for (int x = 0; x < length; x++) {
			p.imag(getImag(x));
			p.real(getReal(x));
			if (p.mod() < min.mod()) {
				min = p;
			}
		}

		return min;
	}


	/**
	 * Returns the maximum magnitude in this signal
	 * @param none
	 */
	public final Complex max() {
		Complex p = new Complex();
		Complex max = new Complex(Double.MIN_VALUE, Double.MIN_VALUE);


		for (int x = 0; x < length; x++) {
			p.imag(getImag(x));
			p.real(getReal(x));
			if (p.mod() > max.mod()) {
				;
			}
			max = p;
		}

		return max;
	}




	/*
	 * single-pixel arithmetic operations
	 */


	/**
	 * Adds a value to a single pixel
	 * @param x length-coordinant
	 * @param r the value to add to the pixel in the real plane
	 * @param i the value to add to the pixel in the imaginary plane
	 */
	public final void add(int x, float r, float i) {
		real.add(x, r);
		imag.add(x, i);
	}


	/**
	 * Subtracts a value from a single pixel
	 * @param x length-coordinant
	 * @param r the value to add to the pixel in the real plane
	 * @param i the value to add to the pixel in the imaginary plane
	 */
	public final void subtract(int x, float r, float i) {
		real.subtract(x, r);
		imag.subtract(x, i);
	}


	/**
	 * Multiply a single pixel by a value
	 * @param x length-coordinant
	 * @param r the value to add to the pixel in the real plane
	 * @param i the value to add to the pixel in the imaginary plane
	 */
	public final void multiply(int x, float r, float i) {
		float a = real.get(x) * r - imag.get(x) * i;
		float b = real.get(x) * i + imag.get(x) * r;

		real.set(x, a);
		imag.set(x, b);
	}


	/**
	 * Divide a single pixel by a value
	 * @param x length-coordinant
	 * @param y Y-coordinant
	 * @param r the value to add to the pixel in the real plane
	 * @param i the value to add to the pixel in the imaginary plane
	 */
	public final void divide(int x, float r, float i) {
		float a;
		float b;
		float mag2;

		mag2 = r * r + i * i;
		a = (real.get(x) * r + imag.get(x) * i) / mag2;
		b = (imag.get(x) * r - real.get(x) * i) / mag2;

		real.set(x, a);
		System.out.println(x + "  " + a);
		imag.set(x, b);
	}


	/**
	 * Adds another ComplexSignal to this signal
	 * @param im the ComplexSignal to add
	 * @return this
	 */
	public final void add(ComplexSignal im) {

		for (int x = 0; x < length; x++) {
			add(x, im.getReal(x), im.getImag(x));
		}

	}


	/**
	 * Subtracts another ComplexSignal from this signal
	 * @param im the ComplexSignal to subtract
	 * @return this
	 */
	public final void subtract(ComplexSignal im) {

		for (int x = 0; x < length; x++) {
			subtract(x, im.getReal(x), im.getImag(x));
		}

	}


	/**
	 * Subtracts the second signal from the first and returns the absolute value
	 */
	public final ComplexSignal diff(ComplexSignal s) {
		real.diff(s.real());
		imag.diff(s.real());

		return this;
	}




	/**
	 * Multiplies this signal by another ComplexSignal
	 * @param im the ComplexSignal to multiply
	 * @return this
	 */
	public final void multiply(ComplexSignal im) {

		for (int x = 0; x < length; x++) {
			multiply(x, im.getReal(x), im.getImag(x));
		}

	}


	/**
	 * Divides this signal by another ComplexSignal
	 * @param im the ComplexSignal to divide
	 * @return this
	 */
	public final void divide(ComplexSignal im) {

		for (int x = 0; x < length; x++) {
			divide(x, im.getReal(x), im.getImag(x));
		}

	}


	/*
	 * signal-wide arithmetic operations
	 */


	/**
	 * Adds a value to all the pixels in this signal
	 * @param r value to be added to the pixels in the real plane
	 * @param i value to be added to the pixels in the imaginary plane
	 * @return this
	 */
	public final ComplexSignal add(float r, float i) {

		for (int x = 0; x < length; x++) {
			add(x, r, i);
		}

		return this;
	}


	/**
	 * Subtracts a value from all the pixels in this signal
	 * @param r value to be subtract from the pixels in the real plane
	 * @param i value to be subtracted from  pixels in the imaginary plane
	 * @return this
	 */
	public final ComplexSignal subtract(float r, float i) {

		for (int x = 0; x < length; x++) {
			subtract(x, r, i);
		}

		return this;
	}


	/**
	 * Multiplies all the pixels in this signal by a value
	 * @param r value to be multiplied by the pixels in the real plane
	 * @param i value to be multiplied by the pixels in the imaginary plane
	 * @return this
	 */
	public final ComplexSignal multiply(float r, float i) {

		for (int x = 0; x < length; x++) {
			multiply(x, r, i);
		}

		return this;
	}


	/**
	 * Divides all the pixels by a value in this signal
	 * @param r value to be divided into the pixels in the real plane
	 * @param i value to be divided into the pixels in the imaginary plane
	 * @return this
	 */
	public final ComplexSignal divide(float r, float i) {

		for (int x = 0; x < length; x++) {
			divide(x, r, i);
		}

		return this;
	}


	/**
	 * Prints the string in integer format.
	 * <DT><DL><DL>-Example of output on an signal with width 100 and height 120:</DT>
	 * <DL>       <DT>100 : 120</DT>
	 * <DT>5 23 54 7 3 23 46 253 23 53 65 34 ...</DT></DL>
	 * <DL>       <DT>100 : 120</DT>
	 * <DT>10 20 32 12 32 56 40 59 42 39 43 ...</DT></DL></DL></DL>
	 */
	public String toString() {
		String	str;

		str = real.toString();
		str += imag.toString();
		return str;
	}


	/**
	 * Makes a deep copy of a Region of Interest
	 * @param r Region of Interest
	 * @return a deep copy of ComplexSignal
	 */
	public Signal copy(ROI r) {
		ComplexSignal c = new ComplexSignal(r.X());

		for (int x = r.ux(); x < r.uy(); x++) {
			c.real.set(x, real.get(x));
			c.imag.set(x, imag.get(x));
		}

		return c;
	}


	/**
	 * Returns the pixel value at the given x value of a Region of Interest in the real plane
	 * @param x  the length coordinant
	 *
	 * @param r   Region of Interest
	 */
	public final float getReal(int x, ROI r) {
		return real.get(x + r.ux() + r.uy());
	}


	/**
	 * Returns the pixel value at the given x value of a Region of Interest in the imaginary plane
	 * @param x  the length coordinant
	 *
	 * @param r   Region of Interest
	 */
	public final float getImag(int x, ROI r) {
		return imag.get(x + r.ux() + r.uy());
	}


	/**
	 * Sets tthe pixel value at the given x value of a Region of Interest in the real plane
	 * @param x  the length coordinant
	 *
	 * @param r   Region of Interest
	 */
	public final void setReal(int x, float v, ROI r) {
		real.set(x + r.ux() + r.uy(), v);
	}


	/**
	 * Sets the pixel value at the given x value of a Region of Interest in the imaginary plane
	 * @param x  the length coordinant
	 *
	 * @param r   Region of Interest
	 */
	public final void setImag(int x, float v, ROI r) {
		imag.set(x + r.ux() + r.uy(), v);
	}


	/**
	 * Sets the pixel value at x to a given value in a Region of Interest
	 * @param x the length coordinant
	 *
	 * @param r the value to set the pixel to in the real plane
	 * @param i the value to set the pixel to in the imaginary plane
	 * @param r2 Region of Interest
	 */
	public final void set(int x, float r, float i, ROI r2) {
		real.set(x, r, r2);
		imag.set(x, i, r2);
	}

	/*
	 * range functions
	 */


	/**
	 * Returns the minimum magnitude in a Region of Interest
	 * @param r Region of Interest
	 */
	public final Complex min(ROI r) {
		Complex p = new Complex();
		Complex min = new Complex(Double.MAX_VALUE, Double.MAX_VALUE);


		for (int x = r.ux(); x < r.lx(); x++) {
			p.imag(getImag(x));
			p.real(getReal(x));
			if (p.mod() < min.mod()) {
				min = p;
			}
		}

		return min;
	}


	/**
	 * Returns the maximum magnitude in a Region of Interest
	 * @param r Region of Interest
	 */
	public final Complex max(ROI r) {
		Complex p = new Complex();
		Complex max = new Complex(Double.MIN_VALUE, Double.MIN_VALUE);


		for (int x = r.ux(); x < r.lx(); x++) {
			p.imag(getImag(x));
			p.real(getReal(x));
			if (p.mod() > max.mod()) {
				;
			}
			max = p;
		}

		return max;
	}



	/*
	 * single-pixel arithmetic operations
	 */


	/**
	 * Adds a value to a single pixel in a Region of Interest
	 * @param x length-coordinant
	 * @param y Y-coordinant
	 * @param r the value to add to the pixel in the real plane
	 * @param i the value to add to the pixel in the imaginary plane
	 * @param r2 Region of Interest
	 */
	public final void add(int x, float r, float i, ROI r2) {
		real.add(x, r, r2);
		imag.add(x, i, r2);
	}


	/**
	 * Subtracts a value from a single pixel in a Region of Interest
	 * @param x length-coordinant
	 * @param y Y-coordinant
	 * @param r the value to add to the pixel in the real plane
	 * @param i the value to add to the pixel in the imaginary plane
	 * @param r2 Region of Interest
	 */
	public final void subtract(int x, float r, float i, ROI r2) {
		real.subtract(x, r, r2);
		imag.subtract(x, i, r2);
	}


	/**
	 * Multiply a single pixel by a value in a Region of Interest
	 * @param x length-coordinant
	 * @param y Y-coordinant
	 * @param r the value to add to the pixel in the real plane
	 * @param i the value to add to the pixel in the imaginary plane
	 * @param r2 Region of Interest
	 */
	public final void multiply(int x, float r, float i, ROI r2) {
		float a = real.get(x) * r - imag.get(x) * i;
		float b = real.get(x) * i + imag.get(x) * r;

		real.set(x, a, r2);
		imag.set(x, b, r2);
	}


	/**
	 * Divide a single pixel by a value in a Region of Interest
	 * @param x length-coordinant
	 * @param y Y-coordinant
	 * @param r the value to add to the pixel in the real plane
	 * @param i the value to add to the pixel in the imaginary plane
	 * @param r2 Region of Interest
	 */
	public final void divide(int x, float r, float i, ROI r2) {
		float a;
		float b;
		float mag2;

		mag2 = r * r + i * i;
		a = (real.get(x) * r + imag.get(x) * i) / mag2;
		b = (imag.get(x) * r - real.get(x) * i) / mag2;
		real.set(x, a, r2);
		imag.set(x, b, r2);
	}



	/*
	 * signal-wide arithmetic operations
	 */


	/**
	 * Adds a value to all the pixels in a Region of Interest
	 * @param r value to be added to the pixels in the real plane
	 * @param i value to be added to the pixels in the imaginary plane
	 * @param r2 Region of Interest
	 * @return this
	 */
	public final ComplexSignal add(float r, float i, ROI r2) {

		for (int x = r2.ux(); x < r2.lx(); x++) {
			add(x, r, i);
		}

		return this;
	}


	/**
	 * Subtracts a value from all the pixels in a Region of Interest
	 * @param r value to be subtract from the pixels in the real plane
	 * @param i value to be subtracted from  pixels in the imaginary plane
	 * @param r2 Region of Interest
	 * @return this
	 */
	public final ComplexSignal subtract(float r, float i, ROI r2) {

		for (int x = r2.ux(); x < r2.lx(); x++) {
			subtract(x, r, i);
		}

		return this;
	}


	/**
	 * Multiplies all the pixels by a value in a Region of Interest
	 * @param r value to be multiplied by the pixels in the real plane
	 * @param i value to be multiplied by the pixels in the imaginary plane
	 * @param r2 Region of Interest
	 * @return this
	 */
	public final ComplexSignal multiply(float r, float i, ROI r2) {

		for (int x = r2.ux(); x < r2.lx(); x++) {
			multiply(x, r, i);
		}

		return this;
	}


	/**
	 * Divides all the pixels by a value in a Region of Interest
	 * @param r value to be divided into the pixels in the real plane
	 * @param i value to be divided into the pixels in the imaginary plane
	 * @param r2 Region of Interest
	 * @return this
	 */
	public final ComplexSignal divide(float r, float i, ROI r2) {

		for (int x = r2.ux(); x < r2.lx(); x++) {
			divide(x, r, i);
		}

		return this;
	}


	/**
	 * Prints the string in integer format.
	 * <DT><DL><DL>-Example of output on an signal with width 100 and height 120:</DT>
	 * <DL>       <DT>100 : 120</DT>
	 * <DT>5 23 54 7 3 23 46 253 23 53 65 34 ...</DT></DL>
	 * <DL>       <DT>100 : 120</DT>
	 * <DT>10 20 32 12 32 56 40 59 42 39 43 ...</DT></DL></DL></DL>
	 * @param r Region of Interest
	 */
	public String toString(ROI r) {
		String	str;

		str = real.toString(r);
		str += imag.toString(r);
		return str;
	}


	/**
	 * Adds a Region of Interest in another GraySignal from a Region of Interest of this signal
	 * @param im the ComplexSignal to add
	 * @param sourceSignal Region of Interest for the Source Signal
	 * @param destSignal Region of Interest for the Destination Signal
	 * @return this
	 */
	public final void add(ComplexSignal im, ROI sourceSignal, ROI destSignal) {

		for (int x = sourceSignal.ux(); x < sourceSignal.lx(); x++) {
			add(x, im.getReal(x - sourceSignal.ux() + destSignal.ux()), im.getImag(x - sourceSignal.ux() + destSignal.ux()));
		}

	}


	/**
	 * Subtracts a Region of Interest in another GraySignal from a Region of Interest of this signal
	 * @param im the ComplexSignal to subtract
	 * @param sourceSignal Region of Interest for the Source Signal
	 * @param destSignal Region of Interest for the Destination Signal
	 * @return this
	 */
	public final void subtract(ComplexSignal im, ROI sourceSignal, ROI destSignal) {

		for (int x = sourceSignal.ux(); x < sourceSignal.lx(); x++) {
			subtract(x, im.getReal(x - sourceSignal.ux() + destSignal.ux()), im.getImag(x - sourceSignal.ux() + destSignal.ux()));
		}

	}


	/**
	 * Multiplies a Region of Interest of another GraySignal by a Region of Interest of this signal
	 * @param im the ComplexSignal to multiply
	 * @param sourceSignal Region of Interest for the Source Signal
	 * @param destSignal Region of Interest for the Destination Signal
	 * @return this
	 */
	public final void multiply(ComplexSignal im, ROI sourceSignal, ROI destSignal) {

		for (int x = sourceSignal.ux(); x < sourceSignal.lx(); x++) {
			multiply(x, im.getReal(x - sourceSignal.ux() + destSignal.ux()), im.getImag(x - sourceSignal.ux() + destSignal.ux()));
		}

	}


	/**
	 * Divides by a Region of Interest in this signal by a Region of Interest of another ComplexSignal
	 * @param im the ComplexSignal to divide
	 * @param sourceSignal Region of Interest for the Source Signal
	 * @param destSignal Region of Interest for the Destination Signal
	 * @return this
	 */
	public final void divide(ComplexSignal im, ROI sourceSignal, ROI destSignal) {

		for (int x = sourceSignal.ux(); x < sourceSignal.lx(); x++) {
			divide(x, im.getReal(x - sourceSignal.ux() + destSignal.ux()), im.getImag(x - sourceSignal.ux() + destSignal.ux()));
		}

	}

}


/*--- formatting done in "My Own Convention" style on 08-08-2000 ---*/

