/*
* Copyright (c) 2005, the JUNG Project and the Regents of the University of
* California All rights reserved.
*
* This software is open-source under the BSD license; see either "license.txt"
* or http://jung.sourceforge.net/license.txt for a description.
*
* Created on Apr 16, 2005
*/
package edu.uci.ics.jung.visualization.transform;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.PathIterator;
import java.awt.geom.Point2D;
import edu.uci.ics.jung.visualization.transform.shape.ShapeTransformer;
/**
*
* Provides methods to map points from one coordinate system to
* another, by delegating to a wrapped AffineTransform (uniform)
* and its inverse.
*
* @author Tom Nelson
*/
public class AffineTransformer implements BidirectionalTransformer, ShapeTransformer {
protected AffineTransform inverse;
/**
* the AffineTransform to use. Initialize to identity
*
*/
protected AffineTransform transform = new AffineTransform();
/**
* create an instance that does not transform points
*
*/
public AffineTransformer() {
// nothing left to do
}
/**
* Create an instance with the supplied transform
*/
public AffineTransformer(AffineTransform transform) {
if(transform != null)
this.transform = transform;
}
/**
* @return Returns the transform.
*/
public AffineTransform getTransform() {
return transform;
}
/**
* @param transform The transform to set.
*/
public void setTransform(AffineTransform transform) {
this.transform = transform;
}
/**
* applies the inverse transform to the supplied point
* @param p
* @return
*/
public Point2D inverseTransform(Point2D p) {
return getInverse().transform(p, null);
}
public AffineTransform getInverse() {
if(inverse == null) {
try {
inverse = transform.createInverse();
} catch (NoninvertibleTransformException e) {
e.printStackTrace();
}
}
return inverse;
}
/**
* getter for scalex
*/
public double getScaleX() {
return transform.getScaleX();
}
/**
* getter for scaley
*/
public double getScaleY() {
return transform.getScaleY();
}
public double getScale() {
return Math.sqrt(transform.getDeterminant());
}
/**
* getter for shear in x axis
*/
public double getShearX() {
return transform.getShearX();
}
/**
* getter for shear in y axis
*/
public double getShearY() {
return transform.getShearY();
}
/**
* get the translate x value
*/
public double getTranslateX() {
return transform.getTranslateX();
}
/**
* get the translate y value
*/
public double getTranslateY() {
return transform.getTranslateY();
}
/**
* applies the transform to the supplied point
*/
public Point2D transform(Point2D p) {
if(p == null) return null;
return transform.transform(p, null);
}
/**
* transform the supplied shape from graph coordinates to
* screen coordinates
* @return the GeneralPath of the transformed shape
*/
public Shape transform(Shape shape) {
GeneralPath newPath = new GeneralPath();
float[] coords = new float[6];
for(PathIterator iterator=shape.getPathIterator(null);
iterator.isDone() == false;
iterator.next()) {
int type = iterator.currentSegment(coords);
switch(type) {
case PathIterator.SEG_MOVETO:
Point2D p = transform(new Point2D.Float(coords[0], coords[1]));
newPath.moveTo((float)p.getX(), (float)p.getY());
break;
case PathIterator.SEG_LINETO:
p = transform(new Point2D.Float(coords[0], coords[1]));
newPath.lineTo((float)p.getX(), (float) p.getY());
break;
case PathIterator.SEG_QUADTO:
p = transform(new Point2D.Float(coords[0], coords[1]));
Point2D q = transform(new Point2D.Float(coords[2], coords[3]));
newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
break;
case PathIterator.SEG_CUBICTO:
p = transform(new Point2D.Float(coords[0], coords[1]));
q = transform(new Point2D.Float(coords[2], coords[3]));
Point2D r = transform(new Point2D.Float(coords[4], coords[5]));
newPath.curveTo((float)p.getX(), (float)p.getY(),
(float)q.getX(), (float)q.getY(),
(float)r.getX(), (float)r.getY());
break;
case PathIterator.SEG_CLOSE:
newPath.closePath();
break;
}
}
return newPath;
}
/**
* transform the supplied shape from graph coordinates to
* screen coordinates
* @return the GeneralPath of the transformed shape
*/
public Shape inverseTransform(Shape shape) {
GeneralPath newPath = new GeneralPath();
float[] coords = new float[6];
for(PathIterator iterator=shape.getPathIterator(null);
iterator.isDone() == false;
iterator.next()) {
int type = iterator.currentSegment(coords);
switch(type) {
case PathIterator.SEG_MOVETO:
Point2D p = inverseTransform(new Point2D.Float(coords[0], coords[1]));
newPath.moveTo((float)p.getX(), (float)p.getY());
break;
case PathIterator.SEG_LINETO:
p = inverseTransform(new Point2D.Float(coords[0], coords[1]));
newPath.lineTo((float)p.getX(), (float) p.getY());
break;
case PathIterator.SEG_QUADTO:
p = inverseTransform(new Point2D.Float(coords[0], coords[1]));
Point2D q = inverseTransform(new Point2D.Float(coords[2], coords[3]));
newPath.quadTo((float)p.getX(), (float)p.getY(), (float)q.getX(), (float)q.getY());
break;
case PathIterator.SEG_CUBICTO:
p = inverseTransform(new Point2D.Float(coords[0], coords[1]));
q = inverseTransform(new Point2D.Float(coords[2], coords[3]));
Point2D r = inverseTransform(new Point2D.Float(coords[4], coords[5]));
newPath.curveTo((float)p.getX(), (float)p.getY(),
(float)q.getX(), (float)q.getY(),
(float)r.getX(), (float)r.getY());
break;
case PathIterator.SEG_CLOSE:
newPath.closePath();
break;
}
}
return newPath;
}
public double getRotation() {
double[] unitVector = new double[]{0,0,1,0};
double[] result = new double[4];
transform.transform(unitVector, 0, result, 0, 2);
double dy = Math.abs(result[3] - result[1]);
double length = Point2D.distance(result[0], result[1], result[2], result[3]);
double rotation = Math.asin(dy / length);
if (result[3] - result[1] > 0) {
if (result[2] - result[0] < 0) {
rotation = Math.PI - rotation;
}
} else {
if (result[2] - result[0] > 0) {
rotation = 2 * Math.PI - rotation;
} else {
rotation = rotation + Math.PI;
}
}
return rotation;
}
@Override
public String toString() {
return "Transformer using "+transform;
}
}