blob: 3e9bb8abb647a21b418d92b0e0d37461dd9a090c [file] [log] [blame]
/* Copyright (C) 2000 Free Software Foundation
This file is part of libjava.
This software is copyrighted work licensed under the terms of the
Libjava License. Please consult the file "LIBJAVA_LICENSE" for
details. */
package java.awt.geom;
import java.awt.*;
import java.io.Serializable;
/**
* @author Tom Tromey <tromey@cygnus.com>
* @date April 16, 2000
*/
/* Status: mostly complete. Search for fixme to see problems.
Also, TYPE_ returns are not handled correctly. */
public class AffineTransform implements Cloneable, Serializable
{
public static final int TYPE_IDENTITY = 0;
public static final int TYPE_FLIP = 64;
public static final int TYPE_GENERAL_ROTATION = 16;
public static final int TYPE_GENERAL_SCALE = 4;
public static final int TYPE_GENERAL_TRANSFORM = 32;
public static final int TYPE_MASK_ROTATION = 24;
public static final int TYPE_MASK_SCALE = 6;
public static final int TYPE_QUADRANT_ROTATION = 8;
public static final int TYPE_TRANSLATION = 1;
public static final int TYPE_UNIFORM_SCALE = 2;
public AffineTransform ()
{
setToIdentity ();
}
public AffineTransform (AffineTransform tx)
{
setTransform (tx);
}
public AffineTransform (float m00, float m10,
float m01, float m11,
float m02, float m12)
{
this.m00 = m00;
this.m10 = m10;
this.m01 = m01;
this.m11 = m11;
this.m02 = m02;
this.m12 = m12;
this.type = 0; // fixme;
}
public AffineTransform (float[] flatmatrix)
{
m00 = flatmatrix[0];
m10 = flatmatrix[1];
m01 = flatmatrix[2];
m11 = flatmatrix[3];
if (flatmatrix.length >= 6)
{
m02 = flatmatrix[4];
m12 = flatmatrix[5];
}
}
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;
this.type = TYPE_GENERAL_TRANSFORM;
}
public AffineTransform (double[] flatmatrix)
{
m00 = flatmatrix[0];
m10 = flatmatrix[1];
m01 = flatmatrix[2];
m11 = flatmatrix[3];
if (flatmatrix.length >= 6)
{
m02 = flatmatrix[4];
m12 = flatmatrix[5];
}
}
public static AffineTransform getTranslateInstance (double tx, double ty)
{
AffineTransform t = new AffineTransform ();
t.setToTranslation (tx, ty);
return t;
}
public static AffineTransform getRotateInstance (double theta)
{
AffineTransform t = new AffineTransform ();
t.setToRotation (theta);
return t;
}
public static AffineTransform getRotateInstance (double theta,
double x, double y)
{
AffineTransform t = new AffineTransform ();
t.rotate (theta, x, y);
return t;
}
public static AffineTransform getScaleInstance (double sx, double sy)
{
AffineTransform t = new AffineTransform ();
t.setToScale (sx, sy);
return t;
}
public static AffineTransform getShearInstance (double shx, double shy)
{
AffineTransform t = new AffineTransform ();
t.setToShear (shx, shy);
return t;
}
public int getType ()
{
return type;
}
public double getDeterminant ()
{
return m00 * m11 - m01 * m10;
}
public void getMatrix (double[] flatmatrix)
{
flatmatrix[0] = m00;
flatmatrix[1] = m10;
flatmatrix[2] = m01;
flatmatrix[3] = m11;
if (flatmatrix.length >= 6)
{
flatmatrix[4] = m02;
flatmatrix[5] = m12;
}
}
public double getScaleX ()
{
return m00;
}
public double getScaleY ()
{
return m11;
}
public double getShearX ()
{
return m01;
}
public double getShearY ()
{
return m10;
}
public double getTranslateX ()
{
return m02;
}
public double getTranslateY ()
{
return m12;
}
public void translate (double tx, double ty)
{
m02 += tx * m00 + ty * m01;
m12 += tx * m10 + ty * m11;
}
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;
}
public void rotate (double theta, double x, double y)
{
translate (x, y);
rotate (theta);
translate (-x, -y);
}
public void scale (double sx, double sy)
{
m00 *= sx;
m01 *= sy;
m10 *= sx;
m11 *= sy;
}
public void shear (double shx, double shy)
{
double n00 = m00 + shx * m01;
double n01 = shx * m00 + m01;
double n10 = m10 * shy + m11;
double n11 = shx * m10 + m11;
m00 = n00;
m01 = n01;
m10 = n10;
m11 = n11;
}
public void setToIdentity ()
{
m00 = m11 = 1;
m01 = m02 = m10 = m12 = 0;
type = TYPE_IDENTITY;
}
public void setToTranslation (double tx, double ty)
{
m00 = m11 = 1;
m01 = m10 = 0;
m02 = tx;
m12 = ty;
type = TYPE_TRANSLATION;
}
public void setToRotation (double theta)
{
double c = Math.cos (theta);
double s = Math.sin (theta);
m00 = c;
m01 = -s;
m02 = 0;
m10 = s;
m11 = c;
m12 = 0;
type = TYPE_GENERAL_ROTATION;
}
public void setToScale (double sx, double sy)
{
m00 = sx;
m01 = m02 = m10 = m12 = 0;
m11 = sy;
type = (sx == sy) ? TYPE_UNIFORM_SCALE : TYPE_GENERAL_SCALE;
}
public void setToShear (double shx, double shy)
{
m00 = m11 = 1;
m01 = shx;
m10 = shy;
m02 = m12 = 0;
type = 0; // FIXME
}
public void setTransform (AffineTransform tx)
{
m00 = tx.m00;
m01 = tx.m01;
m02 = tx.m02;
m10 = tx.m10;
m11 = tx.m11;
m12 = tx.m12;
type = tx.type;
}
public void setTransform (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;
this.type = 0; // FIXME
}
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;
}
public void preConcatenate (AffineTransform tx)
{
double n00 = tx.m00 * m00 + tx.m01 * m10;
double n01 = tx.m00 * m01 + tx.m01 * m11;
double n02 = tx.m00 * m02 + tx.m01 * m12 + tx.m02;
double n10 = tx.m10 * m00 + tx.m11 * m10;
double n11 = tx.m10 * m01 + tx.m11 * m11;
double n12 = tx.m10 * m02 + tx.m11 * m12 + tx.m12;
m00 = n00;
m01 = n01;
m02 = n02;
m10 = n10;
m11 = n11;
m12 = n12;
}
public AffineTransform createInverse ()
throws NoninvertibleTransformException
{
double det = getDeterminant ();
if (det == 0)
throw new NoninvertibleTransformException ("can't invert transform");
double i00 = m11 / det;
double i01 = -m10 / det;
double i02 = 0;
double i10 = m01 / det;
double i11 = -m00 / det;
double i12 = 0;
return new AffineTransform (i00, i01, i02,
i10, i11, i12);
}
public Point2D transform (Point2D src, Point2D dst)
{
if (dst == null)
dst = new Point2D.Double ();
// We compute and set separately to correctly overwrite if
// src==dst.
double x = src.getX ();
double y = src.getY ();
double nx = m00 * x + m01 * y + m02;
double ny = m10 * x + m11 * y + m12;
dst.setLocation (nx, ny);
return dst;
}
public void transform (Point2D[] src, int srcOff,
Point2D[] dst, int dstOff,
int num)
{
while (num-- > 0)
{
dst[dstOff] = transform (src[srcOff], dst[dstOff]);
++srcOff;
++dstOff;
}
}
public void transform (float[] srcPts, int srcOff,
float[] dstPts, int dstOff,
int num)
{
while (num-- > 0)
{
float x = srcPts[srcOff];
float y = srcPts[srcOff + 1];
srcOff += 2;
float nx = (float) (m00 * x + m01 * y + m02);
float ny = (float) (m10 * x + m10 * y + m12);
dstPts[dstOff] = nx;
dstPts[dstOff + 1] = ny;
dstOff += 2;
}
}
public void transform (double[] srcPts, int srcOff,
double[] dstPts, int dstOff,
int num)
{
while (num-- > 0)
{
double x = srcPts[srcOff];
double y = srcPts[srcOff + 1];
srcOff += 2;
double nx = m00 * x + m01 * y + m02;
double ny = m10 * x + m10 * y + m12;
dstPts[dstOff] = nx;
dstPts[dstOff + 1] = ny;
dstOff += 2;
}
}
public void transform (float[] srcPts, int srcOff,
double[] dstPts, int dstOff,
int num)
{
while (num-- > 0)
{
float x = srcPts[srcOff];
float y = srcPts[srcOff + 1];
srcOff += 2;
double nx = m00 * x + m01 * y + m02;
double ny = m10 * x + m10 * y + m12;
dstPts[dstOff] = nx;
dstPts[dstOff + 1] = ny;
dstOff += 2;
}
}
public void transform (double[] srcPts, int srcOff,
float[] dstPts, int dstOff,
int num)
{
while (num-- > 0)
{
double x = srcPts[srcOff];
double y = srcPts[srcOff + 1];
srcOff += 2;
float nx = (float) (m00 * x + m01 * y + m02);
float ny = (float) (m10 * x + m10 * y + m12);
dstPts[dstOff] = nx;
dstPts[dstOff + 1] = ny;
dstOff += 2;
}
}
public Point2D inverseTransform (Point2D src, Point2D dst)
throws NoninvertibleTransformException
{
double det = getDeterminant ();
if (det == 0)
throw new NoninvertibleTransformException ("couldn't invert transform");
if (dst == null)
dst = new Point2D.Double ();
double x = src.getX ();
double y = src.getY ();
double nx = (m11 * x + - m10 * y) / det;
double ny = (m01 * x + - m00 * y) / det;
dst.setLocation (nx, ny);
return dst;
}
public void inverseTransform (double[] srcPts, int srcOff,
double[] dstPts, int dstOff,
int num)
throws NoninvertibleTransformException
{
double det = getDeterminant ();
if (det == 0)
throw new NoninvertibleTransformException ("couldn't invert transform");
while (num-- > 0)
{
double x = srcPts[srcOff];
double y = srcPts[srcOff + 1];
double nx = (m11 * x + - m10 * y) / det;
double ny = (m01 * x + - m00 * y) / det;
dstPts[dstOff] = nx;
dstPts[dstOff + 1] = ny;
dstOff += 2;
srcOff += 2;
}
}
public Point2D deltaTransform (Point2D src, Point2D dst)
{
if (dst == null)
dst = new Point2D.Double ();
double x = src.getX ();
double y = src.getY ();
double nx = m00 * x + m01 * y;
double ny = m10 * x + m11 * y;
dst.setLocation (nx, ny);
return dst;
}
public void deltaTransform (double[] srcPts, int srcOff,
double[] dstPts, int dstOff,
int num)
{
while (num-- > 0)
{
double x = srcPts[srcOff];
double y = srcPts[srcOff + 1];
double nx = m00 * x + m01 * y;
double ny = m10 * x + m11 * y;
dstPts[dstOff] = nx;
dstPts[dstOff + 1] = ny;
dstOff += 2;
srcOff += 2;
}
}
public Shape createTransformedShape (Shape pSrc)
{
// FIXME
return null;
}
public String toString ()
{
// FIXME
return null;
}
public boolean isIdentity ()
{
return (m00 == 1 && m01 == 0 && m02 == 0
&& m10 == 0 && m11 == 1 && m12 == 0);
}
public Object clone ()
{
return new AffineTransform (this);
}
public int hashCode ()
{
// FIXME
return 23;
}
public boolean equals (Object obj)
{
if (! (obj instanceof AffineTransform))
return false;
AffineTransform t = (AffineTransform) obj;
return (m00 == t.m00 && m01 == t.m01 && m02 == t.m02
&& m10 == t.m10 && m11 == t.m11 && m12 == t.m12);
}
// This iterator is used to apply an AffineTransform to some other
// iterator. It is not private because we want to be able to access
// it from the rest of this package.
class Iterator implements PathIterator
{
// The iterator we are applied to.
private PathIterator subIterator;
public Iterator (PathIterator subIterator)
{
this.subIterator = subIterator;
}
public int currentSegment (double[] coords)
{
int r = subIterator.currentSegment (coords);
int count = 0;
switch (r)
{
case SEG_CUBICTO:
count = 3;
break;
case SEG_QUADTO:
count = 2;
break;
case SEG_LINETO:
case SEG_MOVETO:
count = 1;
break;
default:
// Error. But how to report?
case SEG_CLOSE:
break;
}
transform (coords, 0, coords, 0, count);
return r;
}
public int currentSegment (float[] coords)
{
int r = subIterator.currentSegment (coords);
int count = 0;
switch (r)
{
case SEG_CUBICTO:
count = 3;
break;
case SEG_QUADTO:
count = 2;
break;
case SEG_LINETO:
case SEG_MOVETO:
count = 1;
break;
default:
// Error. But how to report?
case SEG_CLOSE:
break;
}
transform (coords, 0, coords, 0, count);
return r;
}
public int getWindingRule ()
{
return subIterator.getWindingRule ();
}
public boolean isDone ()
{
return subIterator.isDone ();
}
public void next ()
{
subIterator.next ();
}
}
private double m00, m01, m02;
private double m10, m11, m12;
private int type;
}