Help with transforms

I

Ian Stanley

Hi,
I have a simple program below where the user can draw rectangles on a panel.
The choice to either rotate or scale any single rectangle should result in
the appropriate action.(after selecting a shape).
However, the selected rectangle is transformed(rotated or scaled) but it
appears to be drawn translated as well.
I am guessing that it has somethig to do with transforming the coordinate
system for that shape.
Is there a way to fix it so that the selected shape is rotated or scaled at
its current location?
Thanking you in advance
Ian.

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
public class SwingDraw
{
public static void main(String[] args)
{
Draw D = new Draw() ;
}
}

interface Constants {
final int RECTANGLE = 1, ROTATE = 2, SCALE = 3;
}

class Draw extends JFrame
implements Constants, ActionListener{
JPanel bp = new JPanel() ;
DrawJPanel djp ;
Container content = getContentPane() ;
JButton rectButton, rotateButton, quitButton, scaleButton ;

Draw() {
super() ;
content.setLayout(new BorderLayout()) ;
djp = new DrawJPanel() ;
bp.add(rectButton = new JButton("Rectangle")) ;
bp.add(rotateButton = new JButton("rotate")) ;
bp.add(scaleButton = new JButton("scale")) ;
bp.add(quitButton = new JButton("Quit")) ;
quitButton.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent
e) {
System.exit(0) ;
}
}) ;
rectButton.addActionListener(this) ;
rotateButton.addActionListener(this) ;
scaleButton.addActionListener(this) ;
content.add(bp, BorderLayout.NORTH) ;
content.add(djp, BorderLayout.CENTER) ;
setSize(750, 500) ;
setVisible(true) ;
}


public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand() ;
switch (cmd.charAt(0)) {
case 'R':
djp.setMode(RECTANGLE) ;
break ;
case 'r':
djp.setMode(ROTATE) ;
break ;
case 's':
djp.setMode(SCALE) ;
break ;
}
}

}
class DrawJPanel extends JPanel
implements Constants
{
Vector v = new Vector();
Shape current_shape = null;
int drawingMode;
public DrawJPanel()
{
addMouseListener(
new MouseAdapter() {
public void mousePressed(MouseEvent evt)
{
int x = evt.getX();
int y = evt.getY();
// check if we hit an existing shape
current_shape = locateRect(x,y);
// if ( current_shape==null)
// {
if (drawingMode == RECTANGLE){
Rectangle2D.Float e = new
Rectangle2D.Float(x, y, 80, 50);
v.add(e);
repaint();
}
else if (drawingMode == ROTATE &&
current_shape != null ){
rotateShape(x,y);
repaint();
}
else if (drawingMode == SCALE &&
current_shape != null ){
scaleShape(x,y);
repaint();
}
}
}
);
}
void setMode(int mode) {
drawingMode = mode ;
}

public Shape locateRect(int x, int y)
{
for (int i = 0; i < v.size(); i++){
Shape s = (Shape)v.elementAt(i);
if (s.contains(x,y) )
return s;
}
return null;
}

public Shape rotateShape(int x, int y)
{
for (int i = 0; i < v.size(); i++){
Shape s = (Shape)v.elementAt(i);
if (s.contains(x,y) ){
AffineTransform tr =
AffineTransform.getRotateInstance(Math.toRadians(45));
Shape ts = tr.createTransformedShape(current_shape);
v.addElement(ts);
v.removeElement(s);
repaint();
}
}
return null;
}

public Shape scaleShape(int x, int y)

{
for (int i = 0; i < v.size(); i++){
Shape s = (Shape)v.elementAt(i);
if (s.contains(x,y) ){
AffineTransform tr =
AffineTransform.getScaleInstance(0.7,0.7);
Shape ts = tr.createTransformedShape(current_shape);
v.addElement(ts);
v.removeElement(s);
repaint();
}
}
return null;
}

public void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
for(int i=0; i<v.size(); i++)
g.draw((Shape)v.elementAt(i));
}
}
 
L

Larry A Barowski

Ian Stanley said:
Hi,
I have a simple program below where the user can draw rectangles on a panel.
The choice to either rotate or scale any single rectangle should result in
the appropriate action.(after selecting a shape).
However, the selected rectangle is transformed(rotated or scaled) but it
appears to be drawn translated as well.
I am guessing that it has somethig to do with transforming the coordinate
system for that shape.
Is there a way to fix it so that the selected shape is rotated or scaled at
its current location?

You want AffineTransform.getRotateInstance(double theta, double x,
double y), but the definition of center point is up to you. You should
probably store the original center rather than computing it from
Shape bounds, to avoid drift. Actually, you should probably store the
original Shape, current rotation, and current scale. Whenever the
the rotation or scale changes, rebuild the transformed object. This
will avoid roundoff errors due to repeated transforming. So v would
contain objects with: original shape, center point, current rotation,
current scale, and transformed shape.


-Larry

Thanking you in advance
Ian.

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
public class SwingDraw
{
public static void main(String[] args)
{
Draw D = new Draw() ;
}
}

interface Constants {
final int RECTANGLE = 1, ROTATE = 2, SCALE = 3;
}

class Draw extends JFrame
implements Constants, ActionListener{
JPanel bp = new JPanel() ;
DrawJPanel djp ;
Container content = getContentPane() ;
JButton rectButton, rotateButton, quitButton, scaleButton ;

Draw() {
super() ;
content.setLayout(new BorderLayout()) ;
djp = new DrawJPanel() ;
bp.add(rectButton = new JButton("Rectangle")) ;
bp.add(rotateButton = new JButton("rotate")) ;
bp.add(scaleButton = new JButton("scale")) ;
bp.add(quitButton = new JButton("Quit")) ;
quitButton.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent
e) {
System.exit(0) ;
}
}) ;
rectButton.addActionListener(this) ;
rotateButton.addActionListener(this) ;
scaleButton.addActionListener(this) ;
content.add(bp, BorderLayout.NORTH) ;
content.add(djp, BorderLayout.CENTER) ;
setSize(750, 500) ;
setVisible(true) ;
}


public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand() ;
switch (cmd.charAt(0)) {
case 'R':
djp.setMode(RECTANGLE) ;
break ;
case 'r':
djp.setMode(ROTATE) ;
break ;
case 's':
djp.setMode(SCALE) ;
break ;
}
}

}
class DrawJPanel extends JPanel
implements Constants
{
Vector v = new Vector();
Shape current_shape = null;
int drawingMode;
public DrawJPanel()
{
addMouseListener(
new MouseAdapter() {
public void mousePressed(MouseEvent evt)
{
int x = evt.getX();
int y = evt.getY();
// check if we hit an existing shape
current_shape = locateRect(x,y);
// if ( current_shape==null)
// {
if (drawingMode == RECTANGLE){
Rectangle2D.Float e = new
Rectangle2D.Float(x, y, 80, 50);
v.add(e);
repaint();
}
else if (drawingMode == ROTATE &&
current_shape != null ){
rotateShape(x,y);
repaint();
}
else if (drawingMode == SCALE &&
current_shape != null ){
scaleShape(x,y);
repaint();
}
}
}
);
}
void setMode(int mode) {
drawingMode = mode ;
}

public Shape locateRect(int x, int y)
{
for (int i = 0; i < v.size(); i++){
Shape s = (Shape)v.elementAt(i);
if (s.contains(x,y) )
return s;
}
return null;
}

public Shape rotateShape(int x, int y)
{
for (int i = 0; i < v.size(); i++){
Shape s = (Shape)v.elementAt(i);
if (s.contains(x,y) ){
AffineTransform tr =
AffineTransform.getRotateInstance(Math.toRadians(45));
Shape ts = tr.createTransformedShape(current_shape);
v.addElement(ts);
v.removeElement(s);
repaint();
}
}
return null;
}

public Shape scaleShape(int x, int y)

{
for (int i = 0; i < v.size(); i++){
Shape s = (Shape)v.elementAt(i);
if (s.contains(x,y) ){
AffineTransform tr =
AffineTransform.getScaleInstance(0.7,0.7);
Shape ts = tr.createTransformedShape(current_shape);
v.addElement(ts);
v.removeElement(s);
repaint();
}
}
return null;
}

public void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
for(int i=0; i<v.size(); i++)
g.draw((Shape)v.elementAt(i));
}
}
 
I

Ian Stanley

Thanks.
But is there a "hack" or a simple way where I can first work out where the
centre of the shape is and apply a translation relative to these coords
and(0,0) . And then apply the rotation which will rotate the shape about it
centre.
I have lookded at the Sun 2d Transform example which rotates/translates
shapes and they always appear centered. I would like try try something like
this(for my level of understanding) and then try to understand/utilise the
api in more detail:--
Calculate the centre of the panel, working out where the center of the shape
is and applying a tranformation involving this "offset".
The Sun tranform example uses the following to center the shape. I have
tried to do similar in my program but without success.
AffineTransform toCenterAt = new AffineTransform();
toCenterAt.concatenate(at);
toCenterAt.translate(-(r.width/2), -(r.height/2));
any further help appreciated.
Ian
ps the link to the complete transform example:
http://java.sun.com/docs/books/tutorial/2d/display/transforming.html


Ian Stanley said:
Hi,
I have a simple program below where the user can draw rectangles on a panel.
The choice to either rotate or scale any single rectangle should result in
the appropriate action.(after selecting a shape).
However, the selected rectangle is transformed(rotated or scaled) but it
appears to be drawn translated as well.
I am guessing that it has somethig to do with transforming the coordinate
system for that shape.
Is there a way to fix it so that the selected shape is rotated or scaled at
its current location?
Thanking you in advance
Ian.

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
import javax.swing.*;
public class SwingDraw
{
public static void main(String[] args)
{
Draw D = new Draw() ;
}
}

interface Constants {
final int RECTANGLE = 1, ROTATE = 2, SCALE = 3;
}

class Draw extends JFrame
implements Constants, ActionListener{
JPanel bp = new JPanel() ;
DrawJPanel djp ;
Container content = getContentPane() ;
JButton rectButton, rotateButton, quitButton, scaleButton ;

Draw() {
super() ;
content.setLayout(new BorderLayout()) ;
djp = new DrawJPanel() ;
bp.add(rectButton = new JButton("Rectangle")) ;
bp.add(rotateButton = new JButton("rotate")) ;
bp.add(scaleButton = new JButton("scale")) ;
bp.add(quitButton = new JButton("Quit")) ;
quitButton.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent
e) {
System.exit(0) ;
}
}) ;
rectButton.addActionListener(this) ;
rotateButton.addActionListener(this) ;
scaleButton.addActionListener(this) ;
content.add(bp, BorderLayout.NORTH) ;
content.add(djp, BorderLayout.CENTER) ;
setSize(750, 500) ;
setVisible(true) ;
}


public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand() ;
switch (cmd.charAt(0)) {
case 'R':
djp.setMode(RECTANGLE) ;
break ;
case 'r':
djp.setMode(ROTATE) ;
break ;
case 's':
djp.setMode(SCALE) ;
break ;
}
}

}
class DrawJPanel extends JPanel
implements Constants
{
Vector v = new Vector();
Shape current_shape = null;
int drawingMode;
public DrawJPanel()
{
addMouseListener(
new MouseAdapter() {
public void mousePressed(MouseEvent evt)
{
int x = evt.getX();
int y = evt.getY();
// check if we hit an existing shape
current_shape = locateRect(x,y);
// if ( current_shape==null)
// {
if (drawingMode == RECTANGLE){
Rectangle2D.Float e = new
Rectangle2D.Float(x, y, 80, 50);
v.add(e);
repaint();
}
else if (drawingMode == ROTATE &&
current_shape != null ){
rotateShape(x,y);
repaint();
}
else if (drawingMode == SCALE &&
current_shape != null ){
scaleShape(x,y);
repaint();
}
}
}
);
}
void setMode(int mode) {
drawingMode = mode ;
}

public Shape locateRect(int x, int y)
{
for (int i = 0; i < v.size(); i++){
Shape s = (Shape)v.elementAt(i);
if (s.contains(x,y) )
return s;
}
return null;
}

public Shape rotateShape(int x, int y)
{
for (int i = 0; i < v.size(); i++){
Shape s = (Shape)v.elementAt(i);
if (s.contains(x,y) ){
AffineTransform tr =
AffineTransform.getRotateInstance(Math.toRadians(45));
Shape ts = tr.createTransformedShape(current_shape);
v.addElement(ts);
v.removeElement(s);
repaint();
}
}
return null;
}

public Shape scaleShape(int x, int y)

{
for (int i = 0; i < v.size(); i++){
Shape s = (Shape)v.elementAt(i);
if (s.contains(x,y) ){
AffineTransform tr =
AffineTransform.getScaleInstance(0.7,0.7);
Shape ts = tr.createTransformedShape(current_shape);
v.addElement(ts);
v.removeElement(s);
repaint();
}
}
return null;
}

public void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
for(int i=0; i<v.size(); i++)
g.draw((Shape)v.elementAt(i));
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,835
Latest member
lila30

Latest Threads

Top