package com.tom_roush.pdfbox.util.awt;
import android.graphics.PointF;
/**
* Represents a affine transformation between 2 points
* @see com.tom_roush.pdfbox.util.Matrix
*
* [ x'] [ m00 m01 m02 ] [ x ] [ m00*x + m01*y + m02 ]
* [ y'] = [ m10 m11 m12 ] [ y ] = [ m10*x + m11*y + m12 ]
* [ 1 ] [ 0 0 1 ] [ 1 ] [ 1 ]
*
* Based on the AWT implementation
*
* @author bomski
* @author Tom Roush
*/
public class AffineTransform
{
private double m00, m10, m01, m11, m02, m12;
/**
* Creates an identity AffineTransform
*
* [ 1 0 0 ]
* [ 0 1 0 ]
* [ 0 0 1 ]
*/
public AffineTransform()
{
m00 = m11 = 1;
}
/**
* Creates a new AffineTransfrom that copies the given AffineTransform
*
* @param tx the AffineTransform to copy from
*/
public AffineTransform(AffineTransform tx)
{
setTransform(tx);
}
/**
* Creates a new AffineTransform with the given values
*
* [ m00 m01 m02 ]
* [ m10 m11 m12 ]
* [ 0 0 1 ]
*
* @param m00 the x scaling component
* @param m10 the y shearing component
* @param m01 the x shearing component
* @param m11 the y scaling component
* @param m02 the x translation component
* @param m12 the y translation component
*/
public AffineTransform(double m00, double m10, double m01, double m11, double m02, double m12)
{
this.m00 = m00;
this.m10 = m10;
this.m01 = m01;
this.m11 = m11;
this.m02 = m02;
this.m12 = m12;
}
/**
* Creates a new AffineTransform with the given values
*
* @param d an array of doubles that holds the values
*/
public AffineTransform(double[] d)
{
m00 = d[0];
m10 = d[1];
m01 = d[2];
m11 = d[3];
if (d.length >= 6)
{
m02 = d[4];
m12 = d[5];
}
}
/**
* Creates an AffineTransform from an android.graphics.Matrix
*
* @param matrix the matrix to copy from
*/
public AffineTransform(android.graphics.Matrix matrix)
{
float[] values = new float[9];
matrix.getValues(values);
m00 = values[0];
m01 = values[1];
m02 = values[2];
m10 = values[3];
m11 = values[4];
m12 = values[5];
}
/**
* Returns a translation transform:
*
* [ 1 0 tx ]
* [ 0 1 ty ]
* [ 0 0 1 ]
*
* @param tx the x translation distance
* @param ty the y translation distance
* @return the translating transform
*/
public static AffineTransform getTranslateInstance(double tx, double ty)
{
AffineTransform t = new AffineTransform();
t.m02 = tx;
t.m12 = ty;
return t;
}
/**
* Returns a scaling transform:
*
* [ sx 0 0 ]
* [ 0 sy 0 ]
* [ 0 0 1 ]
*
* @param sx the x scaling factor
* @param sy the y scaling factor
* @return the scaling transform
*/
public static AffineTransform getScaleInstance(double sx, double sy)
{
AffineTransform t = new AffineTransform();
t.setToScale(sx, sy);
return t;
}
/**
* Copies the values of the given AffineTransform to this one
*
* @param tx the AffineTransform to copy from
*/
public void setTransform(AffineTransform tx)
{
m00 = tx.m00;
m01 = tx.m01;
m02 = tx.m02;
m10 = tx.m10;
m11 = tx.m11;
m12 = tx.m12;
}
/**
* Returns the X coordinate scaling factor of the matrix.
*
* @return m00
*/
public double getScaleX()
{
return m00;
}
/**
* Returns the Y coordinate shearing factor of the matrix.
*
* @return m10
*/
public double getShearY()
{
return m10;
}
/**
* Returns the X coordinate shearing factor of the matrix.
*
* @return m01
*/
public double getShearX()
{
return m01;
}
/**
* Returns the Y coordinate scaling factor of the matrix.
*
* @return m11
*/
public double getScaleY()
{
return m11;
}
/**
* Returns the X coordinate translation factor of the matrix.
*
* @return m02
*/
public double getTranslateX()
{
return m02;
}
/**
* Returns the Y coordinate translation factor of the matrix.
*
* @return m12
*/
public double getTranslateY()
{
return m12;
}
/**
* Returns the matrix of values used in this AffineTransform
*
* @param values the array of values
*/
public void getMatrix(double[] values)
{
values[0] = m00;
values[1] = m10;
values[2] = m01;
values[3] = m11;
values[4] = m02;
values[5] = m12;
}
/**
* Perform this transformation on the given source point, and store the
* result in the destination (creating it if necessary). It is safe for
* src and dst to be the same.
*
* @param src the source point
* @param dst the destination, or null
* @return the transformation of src, in dst if it was non-null
* @throws NullPointerException if src is null
*/
public PointF transform(PointF src, PointF dst)
{
if (dst == null)
dst = new PointF();
double x = src.x;
double y = src.y;
double nx = m00 * x + m01 * y + m02;
double ny = m10 * x + m11 * y + m12;
dst.set((float) nx, (float) ny);
return dst;
}
/**
* Performs a transformation on an array of points
*
* @param srcPts the array of source points
* @param srcOff the starting offset of the source array
* @param dstPts the array of destination points
* @param dstOff the starting offset of the destination array
* @param num the number of points to transform
*/
public void transform(double[] srcPts, int srcOff, double[] dstPts, int dstOff, int num)
{
if (srcPts == dstPts && dstOff > srcOff && num > 1 && srcOff + 2 * num > dstOff)
{
double[] d = new double[2 * num];
System.arraycopy(srcPts, srcOff, d, 0, 2 * num);
srcPts = d;
}
while (--num >= 0)
{
double x = srcPts[srcOff++];
double y = srcPts[srcOff++];
dstPts[dstOff++] = m00 * x + m01 * y + m02;
dstPts[dstOff++] = m10 * x + m11 * y + m12;
}
}
/**
* Performs a transformation on an array of points
*
* @param srcPts the array of source points
* @param srcOff the starting offset of the source array
* @param dstPts the array of destination points
* @param dstOff the starting offset of the destination array
* @param num the number of points to transform
*/
public void transform(float[] srcPts, int srcOff, float[] dstPts, int dstOff, int num)
{
if (srcPts == dstPts && dstOff > srcOff && num > 1 && srcOff + 2 * num > dstOff)
{
float[] f = new float[2 * num];
System.arraycopy(srcPts, srcOff, f, 0, 2 * num);
srcPts = f;
}
while (--num >= 0)
{
float x = srcPts[srcOff++];
float y = srcPts[srcOff++];
dstPts[dstOff++] = (float) (m00 * x + m01 * y + m02);
dstPts[dstOff++] = (float) (m10 * x + m11 * y + m12);
}
}
/**
* Concatenates a scale unto this matrix
*
* @param sx the x scaling factor
* @param sy the y scaling factor
*/
public void scale(double sx, double sy)
{
m00 *= sx;
m01 *= sy;
m10 *= sx;
m11 *= sy;
}
/**
* Concatenates a translation to this matrix
*
* @param tx the x translation distance
* @param ty the y translation distance
*/
public void translate(double tx, double ty)
{
m02 += tx * m00 + ty * m01;
m12 += tx * m10 + ty * m11;
}
public float[] transform(float[] src, float[] dst)
{
if (dst == null)
{
dst = new float[2];
}
float x = src[0];
float y = src[1];
float nx = (float) (m00 * x + m01 * y + m02);
float ny = (float) (m10 * x + m11 * y + m12);
dst[0] = nx;
dst[1] = ny;
return dst;
}
/**
* Concatenates a rotation to this matrix
*
* @param theta the angle to rotate by
*/
public void rotate(double theta)
{
double c = Math.cos(theta);
double s = Math.sin(theta);
double n00 = m00 * c + m01 * s;
double n01 = m00 * -s + m01 * c;
double n10 = m10 * c + m11 * s;
double n11 = m10 * -s + m11 * c;
m00 = n00;
m01 = n01;
m10 = n10;
m11 = n11;
}
/**
* Set this transform to a scale:
*
* [ sx 0 0 ]
* [ 0 sy 0 ]
* [ 0 0 1 ]
*
* @param sx the x scaling factor
* @param sy the y scaling factor
*/
public void setToScale(double sx, double sy)
{
m00 = sx;
m01 = m02 = m10 = m12 = 0;
m11 = sy;
}
/**
* Set this transform to the result of performing the original version of
* this followed by tx. This is commonly used when chaining transformations
* from one space to another. In matrix form:
* <pre>
* [ this ] = [ this ] x [ tx ]
* </pre>
*
* @param tx the transform to concatenate
* @throws NullPointerException if tx is null
* @see #preConcatenate(AffineTransform)
*/
public void concatenate(AffineTransform tx)
{
double n00 = m00 * tx.m00 + m01 * tx.m10;
double n01 = m00 * tx.m01 + m01 * tx.m11;
double n02 = m00 * tx.m02 + m01 * tx.m12 + m02;
double n10 = m10 * tx.m00 + m11 * tx.m10;
double n11 = m10 * tx.m01 + m11 * tx.m11;
double n12 = m10 * tx.m02 + m11 * tx.m12 + m12;
m00 = n00;
m01 = n01;
m02 = n02;
m10 = n10;
m11 = n11;
m12 = n12;
}
/**
* Tests if this matrix is an identity matrix
*
* @return whether this is the identity matrix
*/
public boolean isIdentity()
{
return (m00 == 1 && m01 == 0 && m02 == 0 && m10 == 0 && m11 == 1 && m12 == 0);
}
/**
* Returns this AffineTransform as an android.graphics.Matrix
*
* @return the matrix
*/
public android.graphics.Matrix toMatrix()
{
android.graphics.Matrix retval = new android.graphics.Matrix();
retval.setValues(new float[]{
(float) m00, (float) m01, (float) m02,
(float) m10, (float) m11, (float) m12,
0f, 0f, 1f
});
return retval;
}
}