views:

73

answers:

1

Hi guys ,

I have the following class that rotates an image when i give it the degrees it has to rotate but it is not working as i want. The problem is this, for instance if i rotate 90 degress, the variable "currentRotationAngle" inside the rotateCrossing() is gradually set to 90 after the rotation. This happens because i increase that variable always by the offset (10).

The next time i want to rotate 180 degrees, because the variable is already 90, it only rotates another 90(90 + 90 = 180) instead of making a whole 180 degrees. I tried to fix it by setting the "currentRotationAngle" to 0 in the "stop()" method anytime the rotation finishes but it let the rotation goes back to its starting position.

This is what i want, when i give it the degrees, i want it to rotate exactly to that degrees starting from the last rotation position. Please the following is the class.

public class CrossingPanel extends JPanel{

    private static final long serialVersionUID = 1L;

    // private data members
     private Image crossingImage;
     private int currentRotationAngle;
     private int imageWidth;
     private int imageHeight;
     private AffineTransform affineTransform;
     private boolean clockwise; 
     private static int ROTATE_ANGLE_OFFSET = 10;

     private boolean finishRotation = false;
     private int degreesToTurn;

     private static int LENGTH = 75;
    private static int RAIL_LENGTH = 130;
    private int ARROWLENGTH = 4;
    private static int TICKSIZE = 10;
    private GeneralPath path;
     private int xCoordinate;
     private int yCoordinate;

     private javax.swing.Timer timer;

     private void initialize(){
        //this.crossingImage = getImage("images/railCrossing.JPG");
         this.crossingImage = Toolkit.getDefaultToolkit().getImage("images/crossingsHorizontal.JPG");
        // MediaTracker mt = new MediaTracker(this);
        // mt.addImage(this.crossingImage, 1);
         this.path = new GeneralPath();
         this.imageWidth = this.getCrossingImage().getWidth(this);
         this.imageHeight = this.getCrossingImage().getHeight(this);
         this.affineTransform = new AffineTransform();
         this.setCurrentRotationAngle(0);
         this.setDegreesToTurn(0);
         timer = new javax.swing.Timer(20, new MoveListener());
           // timer.start();
     } 

    public CrossingPanel(int x, int y/*, BufferedImage img*/) {

        this.setxCoordinate(x);
        this.setyCoordinate(y);
        this.setPreferredSize(new Dimension(50, 50));
        this.setBackground(Color.red);
        TitledBorder border = BorderFactory.createTitledBorder("image");
        //this.setBorder(border);
        this.setLayout(new FlowLayout());
        this.initialize();

    }


    public GeneralPath getPath() {
        return path;
    }
    public void setPath(GeneralPath path) {
        this.path = path;
    }

    private void constructInterfaceComponents(){
    }

    private Shape createVerticalRail(){
        //System.out.print("dddd: " + this.LENGTH + "\n");
        this.getPath().moveTo(0, LENGTH);
        this.getPath().lineTo(RAIL_LENGTH,75);
        float cm = 72 / 2.54f;
        float lengthCentimeter = RAIL_LENGTH;

        for (float i = 260.0f, j = 340; i >= 0; i -= 15.0f, j += 20) {
              float tick = i * cm;
            //  path.moveTo(340, i);
            //  path.lineTo(360, i);
        }

        this.getPath().closePath();
        return this.getPath();
    }

    public void paintComponent(Graphics grp){ 

        Rectangle rect = this.getBounds();
        Graphics2D g2d = (Graphics2D)grp;

        //set the background color to black
        g2d.setColor(Color.BLACK);

       // g2d.draw(this.createVerticalRail());

        //set the translation to the mid of the component

        this.getAffineTransform().setToTranslation(this.getxCoordinate(), this.getyCoordinate());

          //rotate with the rotation point as the mid of the image
        this.getAffineTransform().rotate(Math.toRadians(this.getCurrentRotationAngle()), this.getCrossingImage().getWidth(this) /2, 
                                         this.getCrossingImage().getHeight(this)/2);

        //draw the image using the AffineTransform
        g2d.drawImage(this.getCrossingImage(), this.getAffineTransform(), this);
    }


    public void rotateCrossing(int degrees){
        // this condition is there to avoid division of zero
            // and also there is no need to rotate 0 degrees
            if(degrees == 0){
            this.stop();
            return;
        }
        currentRotationAngle += ROTATE_ANGLE_OFFSET;

            if (currentRotationAngle % degrees == 0) {
                timer.stop();
                this.finishRotation = true;
            }

         repaint(); 
    }



     public int getDegreesToTurn() {
        return degreesToTurn;
    }

    public void setDegreesToTurn(int degreesToTurn) {
        this.degreesToTurn = degreesToTurn;
    }



    private class MoveListener implements ActionListener {

            public void actionPerformed(ActionEvent e) {

                rotateCrossing(degreesToTurn);


        }

     }


     void start(int degreesToTurn) {
            if (timer != null) {
                timer.start();
            }
            this.setDegreesToTurn(degreesToTurn);
        }

     void stop() {
            timer.stop();
            this.setCurrentRotationAngle(0);

        }






    public Image getCrossingImage() {
        return crossingImage;
    }
    public void setCrossingImage(Image crossingImage) {
        this.crossingImage = crossingImage;
    }

    public int getCurrentRotationAngle() {
        return currentRotationAngle;
    }
    public void setCurrentRotationAngle(int currentRotationAngle) {
        this.currentRotationAngle = currentRotationAngle;
    }

    public int getImageWidth() {
        return imageWidth;
    }
    public void setImageWidth(int imageWidth) {
        this.imageWidth = imageWidth;
    }

    public int getImageHeight() {
        return imageHeight;
    }
    public void setImageHeight(int imageHeight) {
        this.imageHeight = imageHeight;
    }

    public AffineTransform getAffineTransform() {
        return affineTransform;
    }
    public void setAffineTransform(AffineTransform affineTransform) {
        this.affineTransform = affineTransform;
    }

    public boolean isClockwise() {
        return clockwise;
    }
    public void setClockwise(boolean clockwise) {
        this.clockwise = clockwise;
    }

    public int getxCoordinate() {
        return xCoordinate;
    }
    public void setxCoordinate(int xCoordinate) {
        this.xCoordinate = xCoordinate;
    }

    public int getyCoordinate() {
        return yCoordinate;
    }
    public void setyCoordinate(int yCoordinate) {
        this.yCoordinate = yCoordinate;
    }

    public javax.swing.Timer getTimer() {
        return timer;
    }
    public void setTimer(javax.swing.Timer timer) {
        this.timer = timer;
    }

    public  boolean isFinishRotation() {
        return finishRotation;
    }

    public void setFinishRotation(boolean finishRotation) {
        this.finishRotation = finishRotation;
    }



}

I would like someone to help me fix it.

Thanks Guys.

A: 

This method is quite strange what it the purpose of degrees parameter? I suppose you call this method multiple times with the same degrees value. You should use absolute value for degrees in this case (270 not 180).

    public void rotateCrossing(int degrees){
    // this condition is there to avoid division of zero
        if(degrees == 0){
        this.stop();
        return;
    }
    currentRotationAngle += ROTATE_ANGLE_OFFSET;

        if (currentRotationAngle % degrees == 0) { // this line isn't correct I think
            timer.stop();
            this.finishRotation = true;
        }

     repaint(); 
    }

I suggest following code:

private class MoveListener implements ActionListener {
    private int cyclesToGo;
    public MoveListener(){
        cyclesToGo = CrossingPanel.this.degreesToTurn / ROTATE_ANGLE_OFFSET; // how many time to call repaint
    }   

        public void actionPerformed(ActionEvent e) {
            if (cyclesToGo-- > 0) rotateCrossing();
            else {
                CrossingPanel.this.stop(); // call outer class methods
                 CrossingPanel.this.finishRotation = true; // call outer class methods
           }
       }

}
   // this method increments currentRotationAngle and calles repaint
   public void rotateCrossing(){
        currentRotationAngle += ROTATE_ANGLE_OFFSET;
        repaint(); 
   }
jethro
The degrees parameter helps the second if() condition to stop after it has rotated that degree. The "currentRotationAngle" will be increasing by the offset gradually so when you take the modulo with the degrees then it will make the rotation stop when it has rotated that degrees. For instance if i want to rotate 90 and the "currentRotationAngle" has been incremented by the offset to 90, then the modulo of both is 0, then the rotation will stop. I hope am clear here
kap
but if you want to rotate 90 degrees you must call for (int i=0;i<9;i++) rotateCrossing(90)? to increment currentRotationAngle 9 times. Am I correct?
jethro
the quick fix would be change the setter of setDegreesToTurn body tothis.degreesToTurn = degreesToTurn + currentRotationAngle;and the (currentRotationAngle % degrees == 0) to (currentRotationAngle == degrees). But I would rethink whole design.
jethro
No. When i call rotateCrossing(90) for the first time, it rotates fine. But the "currentRotationAngle" variable is now increamented to 90 by this statement -currentRotationAngle += ROTATE_ANGLE_OFFSET; -in the method. So the next time when you want it to rotate let say 180, because "currentRotationAngle" variable is already 90 it will continue the increament with the offset till 180 meaning that it will rotate additional 90 instead of a complete 180. What am looking for is able to rotate to the degree regardless of the former rotation.
kap
The for() loop you suggested will increase the "currentRotationAngle" variable to i think 90 * 9.
kap
In a simple way the only line where you modify currentRotationAngle is one where you increment it by ROTATE_ANGLE_OFFSET ( 10 degrees). So how do you want to rotate it by 90 degrees calling this method only once?
jethro
Good question. The repaint() method under the rotateCrossing() calls the paintComponent(Graphics grp) method to repaint the interface. In this method the currentRotationAngle is used to recalculate the new position. So it rotates gradual till it reaches the degrees.
kap
So where the currentRotationAngle will be incremented?
jethro
You only need one call of rotateCrossing() because it is the paintComponent(Graphics grp) method that uses the currentRotationAngle to make it rotate. So as long as the modulo is not zero, it will rotate gradually till it reaches the zero;
kap
Look at this currentRotationAngle += ROTATE_ANGLE_OFFSET;inside the rotateCrossing() method.
kap
So what is expected value of currentRotationAngle after first call rotateCrossing(90)?
jethro
It will be 90. Look inside the class variables at the beginning of the class. The offset variable is 10. It will be increamented always by 10 till it reaches the 90 for the first call. In the subsequent calls the increament starts from the last value of currentRotationAngle. This is where am looking for solution so that it will start the counting afresh but won't affect the former rotation
kap
I give up. line currentRotationAngle += ROTATE_ANGLE_OFFSET; in rotateCrossing method is the ONLY place where you increment currentRotationAngle so how is it possible that after calling this method only ONCE. curentRotationAngle will have value 90 instead of 10 (increment step)?
jethro
I understand what you mean. I think you should have looked in my class well. In the class you will see a private class "private class MoveListener implements ActionListener { ..."It is in this private class that when the timer is started it will call the rotateCrossing() in the its actionPerformed() method repeatedly till the timer is stopped, that is why the second if() condition in rotateCrossing() calls the stop() method. That is why it is rotating gradually till the degrees is reached. Maybe you overlooked that part.
kap
Thanks for your code. I will test and see the outcome
kap