001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032:
033: package com.vividsolutions.jump.warp;
034:
035: import Jama.Matrix;
036:
037: import com.vividsolutions.jts.geom.Coordinate;
038:
039: /**
040: * An AffineTransform implementation that is initialized by specifying
041: * three points and the three points they map to.
042: * <p>From http://graphics.lcs.mit.edu/classes/6.837/F01/Lecture07/lecture07.pdf:
043: * <pre>
044: * [ x1_ ] = [ x1 y1 1 0 0 0 ] [ a11 ]
045: * [ y1_ ] = [ 0 0 0 x1 y1 1 ] [ a12 ]
046: * [ x2_ ] = [ x2 y2 1 0 0 0 ] [ a13 ]
047: * [ y2_ ] = [ 0 0 0 x2 y2 1 ] [ a21 ]
048: * [ x3_ ] = [ x3 y3 1 0 0 0 ] [ a22 ]
049: * [ y3_ ] = [ 0 0 0 x3 y3 1 ] [ a23 ]
050: * x_ = X a
051: * Solution: a = Xinv x_
052: * </pre>
053: */
054: public class AffineTransform extends CoordinateTransform {
055: private Matrix a;
056:
057: /**
058: * A transformation that maps p1 to p1_ via a translation (no rotation or shear).
059: * @param p1 a point
060: * @param p1_ the point it maps to
061: */
062: public AffineTransform(Coordinate p1, Coordinate p1_) {
063: Coordinate p2 = new Coordinate(p1.x + 10, p1.y);
064: Coordinate p2_ = new Coordinate(p1_.x + 10, p1_.y);
065: Coordinate p3 = new Coordinate(p1.x, p1.y + 10);
066: Coordinate p3_ = new Coordinate(p1_.x, p1_.y + 10);
067: initialize(p1, p1_, p2, p2_, p3, p3_);
068: }
069:
070: /**
071: * A transformation that maps p1 to p1_ and p2 to p2_ via a translation,
072: * rotation, and scaling (no "relative" shear).
073: * @param p1 a point
074: * @param p1_ the point p1 maps to
075: * @param p2 another point
076: * @param p2_ the point p2 maps to
077: */
078: public AffineTransform(Coordinate p1, Coordinate p1_,
079: Coordinate p2, Coordinate p2_) {
080: Coordinate p3 = rotate90(p1, p2);
081: Coordinate p3_ = rotate90(p1_, p2_);
082: initialize(p1, p1_, p2, p2_, p3, p3_);
083: }
084:
085: /**
086: * A transformation that maps p1 to p1_, p2 to p2_ and p3 to p3_.
087: * @param p1 a point
088: * @param p1_ the point p1 maps to
089: * @param p2 another point
090: * @param p2_ the point p2 maps to
091: * @param p3 another point
092: * @param p3_ the point p3 maps to
093: */
094: public AffineTransform(Coordinate p1, Coordinate p1_,
095: Coordinate p2, Coordinate p2_, Coordinate p3, Coordinate p3_) {
096: initialize(p1, p1_, p2, p2_, p3, p3_);
097: }
098:
099: /**
100: * Determines where a point would end up if it were rotated 90 degrees about
101: * another point.
102: * @param a the fixed point
103: * @param b the point to rotate (b itself will not be changed)
104: * @return b rotated 90 degrees clockwise about a
105: */
106: public static Coordinate rotate90(Coordinate a, Coordinate b) {
107: return new Coordinate(b.y - a.y + a.x, a.x - b.x + a.y);
108: }
109:
110: private void initialize(Coordinate p1, Coordinate p1_,
111: Coordinate p2, Coordinate p2_, Coordinate p3, Coordinate p3_) {
112: double[][] Xarray = { { p1.x, p1.y, 1, 0, 0, 0 },
113: { 0, 0, 0, p1.x, p1.y, 1 }, { p2.x, p2.y, 1, 0, 0, 0 },
114: { 0, 0, 0, p2.x, p2.y, 1 }, { p3.x, p3.y, 1, 0, 0, 0 },
115: { 0, 0, 0, p3.x, p3.y, 1 } };
116: Matrix X = new Matrix(Xarray);
117: double[][] x_array = { { p1_.x }, { p1_.y }, { p2_.x },
118: { p2_.y }, { p3_.x }, { p3_.y } };
119: Matrix x_ = new Matrix(x_array);
120: a = X.solve(x_);
121: }
122:
123: /**
124: * Applies the affine transform to a point.
125: * From http://graphics.lcs.mit.edu/classes/6.837/F01/Lecture07/lecture07.pdf:
126: * <pre>
127: * [ x_ ] = [ a11 a12 a13 ] [ x ]
128: * [ y_ ] = [ a21 a22 a23 ] [ y ]
129: * [ 1 ] = [ 0 0 1 ] [ 1 ]
130: * </pre>
131: * @param c the input to the affine transform
132: * @return the result of applying the affine transform to c
133: */
134: public Coordinate transform(Coordinate c) {
135: double x_ = (a.get(0, 0) * c.x) + (a.get(1, 0) * c.y)
136: + a.get(2, 0);
137: double y_ = (a.get(3, 0) * c.x) + (a.get(4, 0) * c.y)
138: + a.get(5, 0);
139:
140: return new Coordinate(x_, y_);
141: }
142: }
|