问题
I am implementing a java swing application which has a JPanel that serves as a drawing surface. The surface renders (active) different elements. Each element has its own shape and an affine transform which is used for rendering and collision detection (each element is drawn with local coordinates and than transformed with the affine transform - like opengl).
The elements can be moved and rotated on the surface (this is done through transforms). Every time a transform is applied a Area object is created with the shape and the transformation (for accurate collision detection).
The problem is when I rotate the element (for 45 degrees) and then move it by 10 px. When I move it the element moves in the rotated direction which I don't want.
Is there any simple way I can overcome this?
(If my description isnt enough I'll post some example code).
EDIT:
class Element
{
private AffineTransform transform = new AffineTransform();
private Shape shape = new Rectangle(0,0,100,100);
private Area boundingBox;
public void onMouseDrag(MouseEvent e)
{
translate(dx,dy); // dx,dy are calculated from event
}
public void onMouseMove(MouseEvent e)
{
rotate(Math.atan2(dx/dy); // dx,dy are calculated from event
}
public void translate(int dx,int dy)
{
transform.translate(dx,dy);
boundingBox = new Area(shape);
boundingBox.transform(transform);
}
public void rotate(double angle)
{
transform.rotate(Math.toRadians(angle));
boundingBox = new Area(shape);
boundingBox.transform(transform);
}
public void draw(Graphics2D g2d)
{
g2d.setTransform(transform);
g2d.draw(shape);
...
}
}
回答1:
I've modified your code by giving Element position and orientation fields, which you might want to expose through getters/setters (probably defensively copying the Point instance before returning/setting it). updateTransform() simply re-builds the AffineTransform based on the Element's current position and orientation.
public class Element {
private Point position = new Point();
private float orientation;
private AffineTransform transform = new AffineTransform();
private Shape shape = new Rectangle(0, 0, 100, 100);
private Area boundingBox;
public void onMouseDrag(MouseEvent e) {
translate(dx, dy);
}
public void onMouseMove(MouseEvent e) {
rotate(Math.atan2(dx / dy));
}
public void translate(int dx, int dy) {
position.translate(dx, dy);
updateTransform();
}
public void rotate(double angle) {
orientation += Math.toRadians(angle);
updateTransform();
}
private void updateTransform() {
transform.setToIdentity();
transform.translate(position.x, position.y);
transform.rotate(orientation);
// ... update bounding box here ...
}
public void draw(Graphics2D g2d) {
g2d.setTransform(transform);
g2d.draw(shape);
}
}
Also, consider the following approach:
- Change
draw(Graphics2D)todraw(Graphics2D, AffineTransform transform) - Create
AffineTransform Element.getCompositeTransform()which builds the currentAffineTransformand returns it (likeupdateTransform()). - Remove the
transformfield fromElement. - In your render method, do something like:
.
for (Element element : elements) {
AffineTransform transform = element.getCompositeTransform();
element.draw(graphics, transform);
}
Why? This gives you the flexibility to control Element's drawing transform externally. This is useful if you'll build a node graph (like when an Element can have Element children) and you'll recursively render the graph, concatenating transforms. Btw, this approach is pretty much standard in 3D programming.
回答2:
Reverse the order you are applying the transformations. Or unrotate the object, move it, then re-rotate the object. We would really need to see your code (or even pseudocode) to give you a better answer than this.
来源:https://stackoverflow.com/questions/10219088/java-move-a-rotated-shape