001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 *  image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause 
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 
006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009
010package imagingbook.lib.math;
011
012import ij.IJ;
013import imagingbook.lib.math.Complex;
014
015import java.awt.geom.Point2D;
016import java.util.Locale;
017
018public class Complex {
019
020        private final double re;
021        private final double im;
022        
023        public double re() {
024                return this.re;
025        }
026        
027        public double im() {
028                return this.im;
029        }
030
031        public Complex(double re, double im) {
032                this.re = re;
033                this.im = im;
034        }
035
036        public Complex(Point2D p) {
037                this.re = p.getX();
038                this.im = p.getY();
039        }
040
041        public Complex(Complex c) {
042                this.re = c.re;
043                this.im = c.im;
044        }
045
046        /*
047         * Create a complex quantity on the unit circle with angle 'phi'.
048         * e^{\i \phi} = \cos(\phi) + \i \cdot \sin(\phi)
049         */
050        public Complex(double phi) {
051                this.re = Math.cos(phi);
052                this.im = Math.sin(phi);
053        }
054
055        public static Complex[] makeComplexVector(int M) {
056                Complex[] g = new Complex[M];
057                for (int i = 0; i < M; i++) {
058                        g[i] = new Complex(0, 0);
059                }
060                return g;
061        }
062
063        public static Complex[] duplicate(Complex[] g1) {
064                Complex[] g2 = new Complex[g1.length];
065                for (int i = 0; i < g1.length; i++) {
066                        g2[i] = new Complex(g1[i].re, g1[i].im);
067                }
068                return g2;
069        }
070
071
072        public static Complex[] makeComplexVector(double[] signal) {
073                int M = signal.length;
074                Complex[] g = new Complex[M];
075                for (int i = 0; i < M; i++) {
076                        g[i] = new Complex(signal[i], 0);
077                }
078                return g;
079        }
080
081        public static Complex[] makeComplexVector(double[] real, double[] imag) {
082                int M = real.length;
083                Complex[] g = new Complex[M];
084                for (int i = 0; i < M; i++) {
085                        g[i] = new Complex(real[i], imag[i]);
086                }
087                return g;
088        }
089
090        // radius
091        public double abs() {
092                return Math.sqrt(this.abs2());
093        }
094
095        // squared radius
096        public double abs2() {
097                return re * re + im * im;
098        }
099
100        // angle 
101        public double arg() {
102                return Math.atan2(im, re);
103        }
104
105
106        /*
107         *  ---- complex arithmetic ---------------
108         */
109
110        // complex conjugate
111        public Complex conjugate() {
112                return new Complex(this.re, -this.im);
113        }
114
115        public Complex add(Complex c2) {
116                return new Complex(this.re + c2.re,  this.im + c2.im);
117        }
118
119        public Complex mult(double s) {
120                return new Complex(this.re * s, this.im * s);
121        }
122
123        public Complex mult(Complex c2) {
124                // (x1 + i y1)(x2 + i y2) = (x1 x2 + y1 y2) + i (x1 y2 + y1 x2)
125                Complex c1 = this;
126                double x = c1.re * c2.re - c1.im * c2.im;
127                double y = c1.re * c2.im + c1.im * c2.re;
128                return new Complex(x, y);
129        }
130
131        public Complex rotate(double phi) {
132                return this.mult(new Complex(phi));
133        }
134
135        public double distance(Complex c2) {
136                Complex c1 = this;
137                double dRe = c1.re - c2.re;
138                double dIm = c1.im - c2.im;
139                return Math.sqrt(dRe*dRe + dIm*dIm);
140        }
141
142        public double crossProduct(Complex c2) {
143                Complex c1 = this;
144                return c1.re * c2.im - c1.im * c2.re;
145        }
146
147        public double dotProduct(Complex c2) {
148                Complex c1 = this;
149                return c1.re * c2.re + c1.im * c2.im;
150        }
151        
152        public Complex exp(int k) {
153                if (k < 0) throw new IllegalArgumentException("exponent k >= 0 expected");
154                Complex prod = new Complex(1, 0);
155                for (int i = 0; i < k; i++) {
156                        prod = prod.mult(this);
157                }
158                return prod;
159        }
160
161        public String toString() {
162                if (this.im >= 0) {
163                        return String.format(Locale.US, "(%.4f + %.4f i)", this.re, this.im);
164                }
165                else {
166                        return String.format(Locale.US, "(%.4f - %.4f i)", this.re, Math.abs(this.im));
167                }
168        }
169        
170        // -------------------------------------------------------
171        
172        public static void printComplexVector(Complex[] g, String title) {
173                IJ.log("Listing of " + title);
174                for (int i = 0; i < g.length; i++) {
175                        if (g[i] == null)
176                                IJ.log(String.format("%d: ********", i));
177                        else {
178                                double gr = g[i].re;
179                                double gi = g[i].im;
180                                if (gi >= 0) {
181                                        IJ.log(String.format(Locale.US, "%d: %6.2f + %6.2fi", i, gr, Math.abs(gi)));
182                                }
183                                else {
184                                        IJ.log(String.format(Locale.US, "%d: %6.2f - %6.2fi", i, gr, Math.abs(gi)));
185                                }
186                        }
187                }
188        }
189
190
191        //------------ TESTING only ------------------------------
192
193        public static void main(String[] args) {
194                Complex z1 = new Complex(0.3, 0.6);
195                Complex z2 = new Complex(-1, 0.2);
196                System.out.println("z1 = " + z1);
197                System.out.println("z2 = " + z2);
198                Complex z3 = z1.mult(z2);
199                System.out.println("z3 = " + z3);
200                Complex z4 = z2.mult(z1);
201                System.out.println("z4 = " + z4);
202        }
203
204}