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.nonlinear;
011
012import imagingbook.lib.math.Matrix;
013import imagingbook.pub.geometry.mappings.Mapping;
014
015import java.awt.geom.Point2D;
016
017
018/*
019 * 2007: Changed to use the JAMA numerical math package 
020 * (http://math.nist.gov/javanumerics/jama/) instead of JAMPACK.
021 * 2013: changed to use methods from the local matrix library
022 * (based on Apache Common Maths) to solve linear systems of 
023 * equations.
024 */
025
026public class BilinearMapping extends Mapping { 
027        double a1, a2, a3, a4;
028        double b1, b2, b3, b4;
029        
030        BilinearMapping(
031                                        double a1, double a2, double a3, double a4,
032                                        double b1, double b2, double b3, double b4, 
033                                        boolean isInverse) {
034                this.a1 = a1;   this.a2 = a2;   this.a3 = a3;   this.a4 = a4;
035                this.b1 = b1;   this.b2 = b2;   this.b3 = b3;   this.b4 = b4;   
036                this.isInverseFlag = isInverse;         
037        }
038        
039        //map between arbitrary quadrilaterals
040        public static BilinearMapping makeInverseMapping(
041                        Point2D P1, Point2D P2, Point2D P3, Point2D P4, // source quad
042                        Point2D Q1, Point2D Q2, Point2D Q3, Point2D Q4) // target quad
043                {       
044                //define column vectors X, Y
045                double[] x = {Q1.getX(), Q2.getX(), Q3.getX(), Q4.getX()};
046                double[] y = {Q1.getY(), Q2.getY(), Q3.getY(), Q4.getY()};
047                
048                //define matrix M
049                double[][] M = new double[][]
050                        {{P1.getX(), P1.getY(), P1.getX() * P1.getY(), 1},
051                         {P2.getX(), P2.getY(), P2.getX() * P2.getY(), 1},
052                         {P3.getX(), P3.getY(), P3.getX() * P3.getY(), 1},
053                         {P4.getX(), P4.getY(), P4.getX() * P4.getY(), 1}};
054
055                double[] a = Matrix.solve(M, x);                // solve x = M * a = x (a is unknown)
056                double[] b = Matrix.solve(M, y);                // solve y = M * b = y (b is unknown)
057                
058                double a1 = a[0];               double b1 = b[0];
059                double a2 = a[1];               double b2 = b[1];
060                double a3 = a[2];               double b3 = b[2];
061                double a4 = a[3];               double b4 = b[3];
062                   
063                return new BilinearMapping(a1, a2, a3, a4, b1, b2, b3, b4, true);
064        }
065        
066        public double[] applyTo (double[] xy){
067                double x0 = xy[0];
068                double y0 = xy[1];
069                double x1 = a1 * x0 + a2 * y0 + a3 * x0 * y0 + a4;
070                double y1 = b1 * x0 + b2 * y0 + b3 * x0 * y0 + b4;
071                //pnt.setLocation(x1, y1);
072                return new double[] {x1, y1};
073        }       
074                                                
075//      public Point2D applyTo (Point2D pnt){
076//              double x0 = pnt.getX();
077//              double y0 = pnt.getY();
078//              double x1 = a1 * x0 + a2 * y0 + a3 * x0 * y0 + a4;
079//              double y1 = b1 * x0 + b2 * y0 + b3 * x0 * y0 + b4;
080//              //pnt.setLocation(x1, y1);
081//              return new Point2D.Double(x1, y1);
082//      }       
083        
084        public String toString() {
085                return 
086                        "A=(" + a1 + "," + a2 + "," + a3 + "," + a4 + ")" + 
087                        " / " +
088                        "B=(" + b1 + "," + b2 + "," + b3 + "," + b4 + ")" ;
089        }
090
091}