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