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.pub.geometry.mappings.linear;
011
012import imagingbook.lib.math.Matrix;
013import imagingbook.pub.geometry.mappings.Mapping;
014
015
016
017import java.awt.geom.Point2D;
018
019/*
020 * 2013-02-02: 
021 *      Changed applyTo(Point2D) to return a new point (no reuse).
022 *      Changed LinearMapping invert() to return new mapping.
023 *      Changed LinearMapping concat() to return new mapping.
024 * 2015-12-20:
025 *      Duplicated getInverse() to return a LinearMapping.
026 */
027
028public class LinearMapping extends Mapping {
029        
030        protected double 
031                a00 = 1, a01 = 0, a02 = 0,
032                a10 = 0, a11 = 1, a12 = 0,
033                a20 = 0, a21 = 0, a22 = 1;
034                   
035        public LinearMapping() {
036                // creates the identity mapping
037        }
038                   
039        protected LinearMapping (
040                        double a11, double a12, double a13, 
041                        double a21, double a22, double a23,
042                        double a31, double a32, double a33, boolean inv) {
043                this.a00 = a11;  this.a01 = a12;  this.a02 = a13;
044                this.a10 = a21;  this.a11 = a22;  this.a12 = a23;
045                this.a20 = a31;  this.a21 = a32;  this.a22 = a33;
046                isInverseFlag = inv;
047        }
048        
049        protected LinearMapping (LinearMapping lm) {
050                this.a00 = lm.a00;  this.a01 = lm.a01;  this.a02 = lm.a02;
051                this.a10 = lm.a10;  this.a11 = lm.a11;  this.a12 = lm.a12;
052                this.a20 = lm.a20;  this.a21 = lm.a21;  this.a22 = lm.a22;
053                this.isInverseFlag = lm.isInverseFlag;
054        }
055        
056        public double[] applyTo (double[] xy) {
057                return applyTo(xy[0], xy[1]);
058        }
059        
060        public double[] applyTo (double x, double y) {
061                double h =  (a20 * x + a21 * y + a22);
062                double x1 = (a00 * x + a01 * y + a02) / h;
063                double y1 = (a10 * x + a11 * y + a12) / h;
064                // pnt.setLocation(x1, y1);
065                return new double[] {x1, y1};
066        }
067                   
068        public Point2D applyTo (Point2D pnt) {
069                double x = pnt.getX();
070                double y = pnt.getY();
071                double h =  (a20 * x + a21 * y + a22);
072                double x1 = (a00 * x + a01 * y + a02) / h;
073                double y1 = (a10 * x + a11 * y + a12) / h;
074                // pnt.setLocation(x1, y1);
075                return new Point2D.Double(x1, y1);
076        }
077        
078        public LinearMapping getInverse() {
079                if (isInverseFlag)
080                        return this;
081                else {
082                        return this.invert();
083                }
084        }
085        
086        public LinearMapping invert() {
087                LinearMapping lm = new LinearMapping(this);
088                lm.invertDestructive();
089                return lm;
090        }
091        
092        public void invertDestructive() {
093                double det = a00*a11*a22 + a01*a12*a20 + a02*a10*a21 - 
094                                         a00*a12*a21 - a01*a10*a22 - a02*a11*a20;
095                double b11 = (a11*a22 - a12*a21) / det; 
096                double b12 = (a02*a21 - a01*a22) / det; 
097                double b13 = (a01*a12 - a02*a11) / det; 
098                double b21 = (a12*a20 - a10*a22) / det; 
099                double b22 = (a00*a22 - a02*a20) / det; 
100                double b23 = (a02*a10 - a00*a12) / det;
101                double b31 = (a10*a21 - a11*a20) / det; 
102                double b32 = (a01*a20 - a00*a21) / det; 
103                double b33 = (a00*a11 - a01*a10) / det;
104                a00 = b11;              a01 = b12;              a02 = b13;
105                a10 = b21;              a11 = b22;              a12 = b23;
106                a20 = b31;              a21 = b32;              a22 = b33;
107                isInverseFlag = !isInverseFlag;
108        }
109        
110        public LinearMapping concat(LinearMapping B) {  // TODO: this is unfinished and not clean!
111                LinearMapping A = new LinearMapping(this);
112                A.concatDestructive(B);
113                return A;
114        }
115        
116        // concatenates THIS transform matrix A with B: A-> B*A
117        public void concatDestructive(LinearMapping B) {
118                double b11 = B.a00*a00 + B.a01*a10 + B.a02*a20;
119                double b12 = B.a00*a01 + B.a01*a11 + B.a02*a21;
120                double b13 = B.a00*a02 + B.a01*a12 + B.a02*a22;
121                
122                double b21 = B.a10*a00 + B.a11*a10 + B.a12*a20;
123                double b22 = B.a10*a01 + B.a11*a11 + B.a12*a21;
124                double b23 = B.a10*a02 + B.a11*a12 + B.a12*a22;
125                
126                double b31 = B.a20*a00 + B.a21*a10 + B.a22*a20;
127                double b32 = B.a20*a01 + B.a21*a11 + B.a22*a21;
128                double b33 = B.a20*a02 + B.a21*a12 + B.a22*a22;
129                a00 = b11;              a01 = b12;              a02 = b13;
130                a10 = b21;              a11 = b22;              a12 = b23;
131                a20 = b31;              a21 = b32;              a22 = b33;
132        }
133        
134        public double[][] getTransformationMatrix () {
135                return new double[][]
136                                {{a00, a01, a02},
137                                 {a10, a11, a12},
138                                 {a20, a21, a22}};
139        }
140
141        public LinearMapping duplicate() {
142                return (LinearMapping) this.clone();
143        }
144        
145        
146        public double[][] toArray() {
147                double[][] A =
148                        {{a00, a01, a02},
149                         {a10, a11, a12},
150                         {a20, a21, a22}};
151                return A;
152        }
153        
154        public String toString() {
155                return Matrix.toString(toArray());
156        }
157        
158}
159
160
161
162