Top Banner
1.00 Lecture 18 Geometric Transformations in the 2D API
34

1.00 Lecture 18 Geometric Transformations in the 2D API.

Dec 29, 2015

Download

Documents

Ursula Shelton
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: 1.00 Lecture 18 Geometric Transformations in the 2D API.

1.00 Lecture 18

Geometric Transformations

in the 2D API

Page 2: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Transformed Coordinatesin NgonApp

Page 3: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Pixel Coordinatesin NgonApp

static final float SCALE=200.0F;

static final float tx = 1.5F;

static final float ty = 1.5F;

float transX( float x ) {

return ( x + tx ) * SCALE;

}

float transY( float y ) {

return ( y + ty ) * SCALE;

}

Page 4: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Transformations in theCardioid Grapher

Page 5: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Affine Transformations

• The 2D API provides strong support for affine transformations.

• An affine transformation maps 2D coordinates so that the straightness and parallelism of lines are preserved.

• All affine transformations can be represented by a 3x3 floating point matrix.

• There are a number of “primitive” affine transformations that can be combined.

Page 6: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Scaling

Sx 0 0 x Sx *x 0 Sy 0 y = Sy *y 0 0 1 1 1

Page 7: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Scaling Notes

• Basic scaling operations take place with respect to the origin. If the shape is at the origin, it grows. If it is anywhere else, it grows and moves.

• sx, scaling along the X dimension, does not have to equal sy , scaling along the y.

• For instance, to flip a figure vertically about the x-axi

s, scale by sx=1, sy=-1

Page 8: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Reflection as Scaling

1 0 0 x x

0 -1 0 y = -y

0 0 1 1 1

Page 9: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Translation

100

10

01

ty

tx

1

y

x

1

tyy

txx

=

Page 10: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Rotation

100

0)cos()sin(

0)sin()cos(

1

y

x

=

1

)cos()sin(

)sin()cos(

yx

yx

Page 11: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Composing Transformations

• Suppose we want to scale point (x, y) by 2 and then rotate by 90 degrees.

rotate scale

1100

020

002

100

001

010

y

x

Page 12: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Composing Transformations, 2

• Because matrix multiplication is associative, we can rewrite this as

1100

002

020

1100

020

002

100

001

010

y

x

y

x

Page 13: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Composing Transformations, 3

• Because matrix multiplication does not regularly commute, the order of transformations matters. This squares with our geometric intuition.

• If we invert the matrix, we reverse the transformation.

Page 14: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Transformations and the Origin

• When we transform a shape, we transform each of the defining points of the shape, and then redraw it.

• If we scale or rotate a shape that is not anchored at the origin, it will translate as well.

• If we just want to scale or rotate, then we should translate back to the origin, scale or rotate, and then translate back.

Page 15: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Transformations and the Origin, 2

Page 16: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Transformations in the 2D API

• Transformations are represented by instances of the AffineTransform class in the java.awt.geom package.

• Build a compound transform by1. Creating a new instance of AffineTransform

2. Calling methods to build a stack of basic transforms:

last in, first applied:– translate(double tx, double ty)

– scale(double sx, double sy)

– rotate(double theta)

– rotate(double theta, double x, double y) rotates about (x,y)

Page 17: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Transformation Example

baseXf = new AffineTransform();

baseXf.scale( scale, -scale );

baseXf.translate( -uRect.x, -uRect.y );

If we now apply baseXF it will translate first, then scale. Remember in Java® that transforms are built up like a stack, last in, first applied.

Page 18: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Back to Cardioid

Let’s build our coordinate system:

public class Cardioid extends JFrame { private CardioidGraph graph; private Rectangle2D.Float uSpace;

public static void main( String [] args ) { Rectangle2D.Float uS =

new Rectangle2D.Float(-1.5F,1.5F,4.0F,3.0F);Cardioid card = new Cardioid( uS );card.setSize( 640, 480 );card.setVisible( true );

}

Page 19: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Cardioid Cartesian Space

Rectangle2D.Float(-1.5F,1.5F,4.0F,3.0F) represents the area of Cartesian coordinates in which we will draw our graph:

Page 20: 1.00 Lecture 18 Geometric Transformations in the 2D API.

CardioidGraph

public Cardioid( Rectangle2D.Float uS ) { uSpace = uS; graph = new CardioidGraph( uSpace ); . . .

public class CardioidGraph extends GraphPanel implements ActionListener {

public CardioidGraph( Rectangle2D.Float uR ) { super( uR ); . . .

Page 21: 1.00 Lecture 18 Geometric Transformations in the 2D API.

GraphPanel

public class GraphPanel extends JPanel {

protected Rectangle2D.Float uRect;

protected AffineTransform baseXf = null;

protected Dimension curDim = null;

protected double scale;

private GeneralPath axes = null;

public GraphPanel( Rectangle2D.Float uR ) {

uRect = (Rectangle2D.Float) uR.clone();

}

Page 22: 1.00 Lecture 18 Geometric Transformations in the 2D API.

GraphPanel, paintComponent()

public void paintComponent( Graphics g ) {

super.paintComponent( g );

Graphics2D g2 = (Graphics2D) g;

if ( ! getSize().equals( curDim ) )

doResize();

drawAxes( g2 );

drawGrid( g2 );

}

Page 23: 1.00 Lecture 18 Geometric Transformations in the 2D API.

GraphPanel, doResize()

private void doResize() { curDim = getSize(); hScale = curDim.width / uRect.width; vScale = curDim.height / uRect.height; scale = Math.min( hScale, vScale ); baseXf = new AffineTransform(); baseXf.scale( scale, -scale ); baseXf.translate( -uRect.x, -uRect.y );

axes = createAxes(); grid = createGrid();}

Page 24: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Creating and Drawing the Axes

private GeneralPath createAxes() { GeneralPath path = new GeneralPath(); path.moveTo( uRect.x, 0F ); path.lineTo( uRect.x + uRect.width, 0F ); path.moveTo( 0F, uRect.y ); path.lineTo( 0F, uRect.y - uRect.height ); return path;}private void drawAxes( Graphics2D g2 ) { g2.setPaint( Color.green ); g2.setStroke( new BasicStroke(3 ) ); g2.draw(baseXf.createTransformedShape(axes));}

Page 25: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Initializing CardioidGraph

Page 26: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Initializing CardioidGraph,2public CardioidGraph( Rectangle2D.Float uR ) { super( uR ); diam = uRect.width / 4; hub = new Ellipse2D.Float(0F, -diam/2, diam, diam); tick = uRect.width / 40; wheel = new GeneralPath(); Shape s = new Ellipse2D.Double(diam, -diam/2,diam, diam);

wheel.append( s, false ); wheel.moveTo( 2*diam, 0F ); wheel.lineTo( 2*diam + tick, 0F );}

Page 27: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Timers• Swing provides a utility class called Timer that makes it simpler to buil

d animations.• Timers tick at an interval you can set, and the ticks are reported as Act

ionEvents.

public class TimerUser implements ActionListener { private Timer timer = null; private int tIval = 100; // interval in milliseconds

public TimerUser(){ timer = new Timer( tIval, this ); }

public void start(){ timer.start(); }

public void actionPerformed( ActionEvent e ){ /*do repeated action on every tick*/ }

Page 28: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Timer Methods

Timer( int tickMillis, ActionListener l )

void start()

void stop()

boolean isRunning()

void setRepeats(boolean repeats)

boolean isRepeats()

void setCoalesce(boolean coalesce)

boolean isCoalesce()

Page 29: 1.00 Lecture 18 Geometric Transformations in the 2D API.

CardioidGraph, start()

public void start() { if ( timer != null ) { timer.stop(); } timer = new Timer( tIval, this ); curve = new GeneralPath(); curve.moveTo( 2F, 0F ); tCount = 0; repaint(); timer.start();}

Page 30: 1.00 Lecture 18 Geometric Transformations in the 2D API.

CardioidGraph,actionPerformed()

public void actionPerformed( ActionEvent e ) { tCount++; double theta = tCount * Math.PI / 180; double sint = Math.sin( theta ); double cost = Math.cos( theta ); double cx = cost + cost*cost; double cy = sint + sint*cost; curve.lineTo( (float)cx, (float) cy ); if ( tCount >= 360 ) {

timer.stop();timer = null;

} repaint();}

Page 31: 1.00 Lecture 18 Geometric Transformations in the 2D API.

CardioidGraph,paintComponent()

public void paintComponent( Graphics g ) { super.paintComponent( g ); Graphics2D g2 = (Graphics2D) g; drawHub( g2 ); drawCurve( g2 ); drawWheel( g2 );}

Page 32: 1.00 Lecture 18 Geometric Transformations in the 2D API.

CardioidGraph, drawCurve()private void drawCurve( Graphics2D g2 ) { if ( curve == null ) return; // make curve translucent Composite c = g2.getComposite(); Composite hc = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, .5F ); g2.setComposite( hc );

g2.setPaint( Color.red ); g2.setStroke( new BasicStroke( 2 ) ); g2.draw( baseXf.createTransformedShape( curve ) ); g2.setComposite( c );}

Page 33: 1.00 Lecture 18 Geometric Transformations in the 2D API.

Geometry of the Cardioid

Page 34: 1.00 Lecture 18 Geometric Transformations in the 2D API.

CardioidGraph, drawWheel()private void drawWheel( Graphics2D g2 ) { Composite c = g2.getComposite(); Composite hc = AlphaComposite.getInstance( AlphaComposite.SRC_OVER, .5F ); g2.setComposite( hc ); g2.setPaint( Color.orange ); g2.setStroke( new BasicStroke( 2 ) ); double theta = tCount * Math.PI / 180; AffineTransform whlXf = new AffineTransform(baseXf); whlXf.rotate( theta, diam/2, 0.0 ); whlXf.rotate( theta, 3*diam/2, 0.0 ); g2.draw( whlXf.createTransformedShape( wheel ) ); g2.setComposite( c );}