001: /*
002: * $RCSfile: WarpQuadratic.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.1 $
009: * $Date: 2005/02/11 04:57:25 $
010: * $State: Exp $
011: */
012: package javax.media.jai;
013:
014: import java.awt.Rectangle;
015: import java.awt.geom.Point2D;
016:
017: /**
018: * A quadratic-based description of an image warp.
019: *
020: * <p> The source position (x', y') of a point (x, y) is given by the
021: * quadratic bivariate polynomials:
022: *
023: * <pre>
024: * x' = p(x, y) = c1 + c2*x + c3*y + c4*x^2 + c5*x*y + c6*y^2
025: * y' = q(x, y) = c7 + c8*x + c9*y + c10*x^2 + c11*x*y + c12*y^2
026: * </pre>
027: *
028: * <p> <code>WarpQuadratic</code> is marked final so that it may be
029: * more easily inlined.
030: *
031: * @see WarpPolynomial
032: *
033: */
034: public final class WarpQuadratic extends WarpPolynomial {
035:
036: private float c1, c2, c3, c4, c5, c6; // coefficients for X
037: private float c7, c8, c9, c10, c11, c12; // coefficients for Y
038:
039: /**
040: * Constructs a <code>WarpQuadratic</code> with a given transform mapping
041: * destination pixels into source space. Note that this is
042: * a backward mapping as opposed to the forward mapping used in
043: * AffineOpImage. The coeffs arrays must each contain 6 floats
044: * corresponding to the coefficients c1, c2, etc. as shown in the
045: * class comment.
046: *
047: * @param xCoeffs The six destination to source transform coefficients for
048: * the X coordinate.
049: * @param yCoeffs The six destination to source transform coefficients for
050: * the Y coordinate.
051: * @param preScaleX The scale factor to apply to input (dest) X positions.
052: * @param preScaleY The scale factor to apply to input (dest) Y positions.
053: * @param postScaleX The scale factor to apply to the result of the
054: * X polynomial evaluation
055: * @param postScaleY The scale factor to apply to the result of the
056: * Y polynomial evaluation
057: * @throws IllegalArgumentException if the xCoeff and yCoeff arrays
058: * do not each have size entries.
059: */
060: public WarpQuadratic(float[] xCoeffs, float[] yCoeffs,
061: float preScaleX, float preScaleY, float postScaleX,
062: float postScaleY) {
063: super (xCoeffs, yCoeffs, preScaleX, preScaleY, postScaleX,
064: postScaleY);
065:
066: if (xCoeffs.length != 6 || yCoeffs.length != 6) {
067: throw new IllegalArgumentException(JaiI18N
068: .getString("WarpQuadratic0"));
069: }
070:
071: c1 = xCoeffs[0];
072: c2 = xCoeffs[1];
073: c3 = xCoeffs[2];
074: c4 = xCoeffs[3];
075: c5 = xCoeffs[4];
076: c6 = xCoeffs[5];
077:
078: c7 = yCoeffs[0];
079: c8 = yCoeffs[1];
080: c9 = yCoeffs[2];
081: c10 = yCoeffs[3];
082: c11 = yCoeffs[4];
083: c12 = yCoeffs[5];
084: }
085:
086: /**
087: * Constructs a <code>WarpQuadratic</code> with pre- and
088: * post-scale factors of 1.
089: *
090: * @param xCoeffs The 6 destination to source transform coefficients for
091: * the X coordinate.
092: * @param yCoeffs The 6 destination to source transform coefficients for
093: * the Y coordinate.
094: * @throws IllegalArgumentException if the xCoeff and yCoeff arrays
095: * do not each have size entries.
096: */
097: public WarpQuadratic(float[] xCoeffs, float[] yCoeffs) {
098: this (xCoeffs, yCoeffs, 1.0F, 1.0F, 1.0F, 1.0F);
099: }
100:
101: /**
102: * Computes the source subpixel positions for a given rectangular
103: * destination region, subsampled with an integral period. The
104: * destination region is specified using normal integral (full
105: * pixel) coordinates. The source positions returned by the
106: * method are specified in floating point.
107: *
108: * @param x The minimum X coordinate of the destination region.
109: * @param y The minimum Y coordinate of the destination region.
110: * @param width The width of the destination region.
111: * @param height The height of the destination region.
112: * @param periodX The horizontal sampling period.
113: * @param periodY The vertical sampling period.
114: *
115: * @param destRect A <code>float</code> array containing at least
116: * <code>2*((width+periodX-1)/periodX)*
117: * ((height+periodY-1)/periodY)</code>
118: * elements, or <code>null</code>. If <code>null</code>, a
119: * new array will be constructed.
120: *
121: * @return A reference to the <code>destRect</code> parameter if
122: * it is non-<code>null</code>, or a new
123: * <code>float</code> array otherwise.
124: * @throws ArrayBoundsException if destRect is too small
125: */
126: public float[] warpSparseRect(int x, int y, int width, int height,
127: int periodX, int periodY, float[] destRect) {
128:
129: //XXX: This method should do its calculations in doubles
130:
131: if (destRect == null) {
132: destRect = new float[((width + periodX - 1) / periodX)
133: * ((height + periodY - 1) / periodY) * 2];
134: }
135:
136: //
137: // x' = c1 + c2*x + c3*y + c4*x^2 + c5*x*y + c6*y^2
138: // y' = c7 + c8*x + c9*y + c10*x^2 + c11*x*y + c12*y^2
139: //
140:
141: float px1 = periodX * preScaleX; // powers for periodX
142: float px2 = px1 * px1;
143:
144: // Delta delta x for both polys.
145: float ddx = c4 * 2 * px2;
146: float ddy = c10 * 2 * px2;
147:
148: float x1 = (x + 0.5F) * preScaleX; // powers for x
149: float x2 = x1 * x1;
150:
151: width += x;
152: height += y;
153: int index = 0;
154:
155: for (int j = y; j < height; j += periodY) {
156: // Pre-scaled input coordinates and step.
157: float y1 = (j + 0.5F) * preScaleY; // powers for current y
158: float y2 = y1 * y1;
159:
160: // The warped position for the first point of the current line
161: float wx = c1 + c2 * x1 + c3 * y1 + c4 * x2 + c5 * x1 * y1
162: + c6 * y2;
163: float wy = c7 + c8 * x1 + c9 * y1 + c10 * x2 + c11 * x1
164: * y1 + c12 * y2;
165:
166: // Delta x and delta y
167: float dx = c2 * px1 + c4 * (2 * x1 * px1 + px2) + c5 * px1
168: * y1;
169: float dy = c8 * px1 + c10 * (2 * x1 * px1 + px2) + c11
170: * px1 * y1;
171:
172: for (int i = x; i < width; i += periodX) {
173: destRect[index++] = wx * postScaleX - 0.5F;
174: destRect[index++] = wy * postScaleY - 0.5F;
175:
176: wx += dx;
177: wy += dy;
178: dx += ddx;
179: dy += ddy;
180: }
181: }
182:
183: return destRect;
184: }
185:
186: /**
187: * Computes the source point corresponding to the supplied point.
188: *
189: * <p>This method returns the value of <code>pt</code> in the following
190: * code snippet:
191: *
192: * <pre>
193: * double x1 = (destPt.getX() + 0.5F)*preScaleX;
194: * double x2 = x1*x1;
195: *
196: * double y1 = (destPt.getY() + 0.5F)*preScaleY;
197: * double y2 = y1*y1;
198: *
199: * double x = c1 + c2*x1 + c3*y1 + c4*x2 + c5*x1*y1 + c6*y2;
200: * double y = c7 + c8*x1 + c9*y1 + c10*x2 + c11*x1*y1 + c12*y2;
201: *
202: * Point2D pt = (Point2D)destPt.clone();
203: * pt.setLocation(x*postScaleX - 0.5, y*postScaleY - 0.5);
204: * </pre>
205: * </p>
206: *
207: * @param destPt the position in destination image coordinates
208: * to map to source image coordinates.
209: *
210: * @return a <code>Point2D</code> of the same class as
211: * <code>destPt</code>.
212: *
213: * @throws IllegalArgumentException if <code>destPt</code> is
214: * <code>null</code>.
215: *
216: * @since JAI 1.1.2
217: */
218: public Point2D mapDestPoint(Point2D destPt) {
219: if (destPt == null) {
220: throw new IllegalArgumentException(JaiI18N
221: .getString("Generic0"));
222: }
223:
224: double x1 = (destPt.getX() + 0.5F) * preScaleX;
225: double x2 = x1 * x1;
226:
227: double y1 = (destPt.getY() + 0.5F) * preScaleY;
228: double y2 = y1 * y1;
229:
230: double x = c1 + c2 * x1 + c3 * y1 + c4 * x2 + c5 * x1 * y1 + c6
231: * y2;
232: double y = c7 + c8 * x1 + c9 * y1 + c10 * x2 + c11 * x1 * y1
233: + c12 * y2;
234:
235: Point2D pt = (Point2D) destPt.clone();
236: pt.setLocation(x * postScaleX - 0.5, y * postScaleY - 0.5);
237:
238: return pt;
239: }
240: }
|