We're a community of 1.1M IT Pros here for help, advice, solutions, professional growth and fun. Join us!
1,080,561 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Start New Discussion Reply to this Discussion

Java Graphics Rotation

I have to draw a Circular gauge using Java Graphics. Somewhat similar to the attached image, the circular gauge without the black border as in image.
I tried to use two methodologies but none of them is working perfectly
Firstly, I tried to draw everything using Java Graphics and then rotate the image as per the required input
Following is the code for that

public void paint(Graphics g)
    {
        try {
            centerX = this.getWidth() / 2;
            centerY = this.getHeight() / 2;
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setPaint(new Color(74,74,86));
            g2d.fillRect(0, 0, centerX * 2, centerY * 2);
            AffineTransform affTransform = g2d.getTransform();
            AffineTransform transform = (AffineTransform) (affTransform.clone());
            g2d.transform(transform.getRotateInstance(-this.getHeadingValue() / 57.29, centerX, centerY));
            g2d.setStroke(new BasicStroke(2));
            g2d.setPaint(Color.WHITE);
            for(int i=0;i<36;i++)
            {
            AffineTransform affineTransform = g2d.getTransform();
            AffineTransform newTransform = (AffineTransform)(affineTransform.clone());
            g2d.transform(newTransform.getRotateInstance((10*i)/57.29,centerX,centerY));
            g2d.drawLine(centerX,3,centerX,18);
            if(i%9==0)
            {
            g2d.setStroke(new BasicStroke(1));
            g2d.drawLine(centerX,60,centerX,centerY);
            g2d.setStroke(new BasicStroke(2));
            g2d.setFont(new Font("Sanserif",Font.PLAIN,20));
            if(i==0) g2d.drawString("N",this.getWidth()/2-5,40);
            if(i==9) g2d.drawString("E",this.getWidth()/2-5,40);
            if(i==18) g2d.drawString("S",this.getWidth()/2-7,40);
            if(i==27) g2d.drawString("W",this.getWidth()/2-8,40);
            }
            else if(i%3==0)
            {
            g2d.setFont(new Font("Sanserif",Font.PLAIN,16));
            if(i>=10)
            g2d.drawString(Integer.toString(i),this.getWidth()/2-8,40);
            else
            g2d.drawString(Integer.toString(i),this.getWidth()/2-5,40);
            }
            g2d.setTransform(affineTransform);
            }
            g2d.setTransform(affTransform);
            g2d.drawImage(img, centerX - 25, centerY - 25, null);
        } catch (Exception ex) {
            Logger.getLogger(HeadingCircular.class.getName()).log(Level.SEVERE, null, ex);
        }

        
    }

Here

Image img

is a image object which holds the image of plane to be drawn in the center.
The problem with this methodology is that I am getting shaky mater. The digits and ticks seems to be shaking as the gauge rotates . I need the gauge to rotate smoothly

In Second methodology I tried using an Image instead of drawing the ticks and circular scale and rotating the image as per the input. Following is the code for that methodology

public void paint(Graphics g)
    {
        try {
            centerX = this.getWidth() / 2;
            centerY = this.getHeight() / 2;
            Graphics2D g2d = (Graphics2D) g;
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setPaint(new Color(74,74,86));
            g2d.fillRect(0, 0, centerX * 2, centerY * 2);
            AffineTransform affTransform = g2d.getTransform();
            AffineTransform transform = (AffineTransform) (affTransform.clone());
            g2d.transform(transform.getRotateInstance(-this.getHeadingValue() / 57.29, centerX, centerY));
            
            Image image = ImageIO.read(getClass().getResource("/images/heading_scale.PNG"));
            g2d.drawImage(image,0,0, null);
            g2d.setTransform(affTransform);
            g2d.drawImage(img, centerX - 25, centerY - 25, null);
        } catch (Exception ex) {
            Logger.getLogger(HeadingCircular.class.getName()).log(Level.SEVERE, null, ex);
        }

        
    }

Now the ticks and labels are not shaking,But the problem in using the image is that now the gauge is Jerky. Instead of running smoothly itn run in jerky motion.

I don't know how should I code so that the gauge runs smoothly without any shakes or jerks. Please guide me through it

Attachments heading_indicator[1].gif 32.1KB
4
Contributors
7
Replies
1 Day
Discussion Span
2 Years Ago
Last Updated
9
Views
Question
Answered
gunjannigam
Junior Poster
147 posts since Aug 2009
Reputation Points: 40
Solved Threads: 15
Skill Endorsements: 0

Move as much code as possible out of paint(...) - eg read the image file or create the new Font just once at startup, not on every call to paint(...).
How and how often are you updating? You should be using a javax.swing.Timer to call update the heading then repaint() pretty frequently, eg 50 mSec

JamesCherrill
... trying to help
Moderator
8,660 posts since Apr 2008
Reputation Points: 2,636
Solved Threads: 1,475
Skill Endorsements: 33

that so hard to speak about that, if you really needed some hepl, then you have to send runnable example,

shots to the dark, common mistakes

paintCOmponent instead of paint

setOpaque(false)

mKorbel
Nearly a Posting Virtuoso
1,228 posts since Feb 2011
Reputation Points: 482
Solved Threads: 244
Skill Endorsements: 14

I would agree with the above suggestions to get the ImageIO.read() out of the paint() method and override paintComponent() instead of paint() unless this is an AWT Applet.

I'd also like to mention that you don't necessarily need to create another rotated instance of AffineTransform here

AffineTransform transform = (AffineTransform) (affTransform.clone());
            g2d.transform(transform.getRotateInstance(-this.getHeadingValue() / 57.29, centerX, centerY));

You should be able to simply call

g2d.rotate(-this.getHeadingValue() / 57.29, centerX, centerY)

and draw the image. Since you're restoring the original transform anyway, you can operate directly with the current transform of the graphics context.

Ezzaral
null
Moderator
16,126 posts since May 2007
Reputation Points: 3,294
Solved Threads: 875
Skill Endorsements: 28

Move as much code as possible out of paint(...) - eg read the image file or create the new Font just once at startup, not on every call to paint(...).
How and how often are you updating? You should be using a javax.swing.Timer to call update the heading then repaint() pretty frequently, eg 50 mSec

I am updating at a higher rate 25msec. I am using TimerTask instead of javax.swing.Timer to schedule my task

that so hard to speak about that, if you really needed some hepl, then you have to send runnable example,

shots to the dark, common mistakes

paintCOmponent instead of paint

setOpaque(false)

I have tried using the paintComponent and set as dark example. I am attaching three codes with this. Main,java draws the current component. UDPClient sends the data to Main.java through UDP protocol. I have to finally update my data using UDP protocl

I would agree with the above suggestions to get the ImageIO.read() out of the paint() method and override paintComponent() instead of paint() unless this is an AWT Applet.

I'd also like to mention that you don't necessarily need to create another rotated instance of AffineTransform here

AffineTransform transform = (AffineTransform) (affTransform.clone());
            g2d.transform(transform.getRotateInstance(-this.getHeadingValue() / 57.29, centerX, centerY));

You should be able to simply call

g2d.rotate(-this.getHeadingValue() / 57.29, centerX, centerY)

and draw the image. Since you're restoring the original transform anyway, you can operate directly with the current transform of the graphics context.

I have tried using

AffineTransform transform = (AffineTransform) (affTransform.clone());
            g2d.transform(transform.getRotateInstance(-this.getHeadingValue() / 57.29, centerX, centerY));

but still no change

I have also attached a GIF which shows my current output. You can clearly see the text strings are shaking. What should I do to make them smooth rotating

Attachments 1.gif 754.52KB Main.java (3.23KB) UDPClient.java (4.15KB) plane.PNG 1.64KB HeadingCircular.java (3.92KB)
gunjannigam
Junior Poster
147 posts since Aug 2009
Reputation Points: 40
Solved Threads: 15
Skill Endorsements: 0

Main,java draws the current component. UDPClient sends the data to Main.java through UDP protocol. I have to finally update my data using UDP protocl

Does the program have to perform the UDP data transfer for every paint? If so, is this what is limiting your re-draw rate?
What Thread is the UDP activity happening on - is it called directly or indirectly from paint or paintComponent? If so, you may be blocking Swing's event dispatch thread which will cause jerky screen refreshes.

JamesCherrill
... trying to help
Moderator
8,660 posts since Apr 2008
Reputation Points: 2,636
Solved Threads: 1,475
Skill Endorsements: 33

I never seen good graphics outPut, sure excepts Assemblers hardCoded, but

if you are using java.util.Timer, then all your threads would be better
- invoke single thread from Executor and with implements Runnable too,
- outPut from any backGround threads to GUI must be packed into invokeLater

mKorbel
Nearly a Posting Virtuoso
1,228 posts since Feb 2011
Reputation Points: 482
Solved Threads: 244
Skill Endorsements: 14

Does the program have to perform the UDP data transfer for every paint? If so, is this what is limiting your re-draw rate?
What Thread is the UDP activity happening on - is it called directly or indirectly from paint or paintComponent? If so, you may be blocking Swing's event dispatch thread which will cause jerky screen refreshes.

Yes the program does need to perform UDP data transfer for every paint.
I have a TimerTask which is called to first listen data by UDP and then paintComponent is called from the same object
As I have mentioned earlier I have implemented the code using two ways, firstly by drawing the Ticks and Text by Java Graphics. In this method I am getting shaky texts as I have shown in the above attached image. The texts are shaking their as they rotate
For solving the shaking problem I tried to use a second methodology in which I was drawing image, which consists of Tick and text labels. Since it was a image the text labels were not shaking but in that case I was getting jerky motion but now after using your suggestion of taking ImageIO.read the in second method I am getting a smooth motion
Thanks for your help

Attachments 2.gif 576.5KB
gunjannigam
Junior Poster
147 posts since Aug 2009
Reputation Points: 40
Solved Threads: 15
Skill Endorsements: 0
Question Answered as of 2 Years Ago by JamesCherrill, mKorbel and Ezzaral

This question has already been solved: Start a new discussion instead

Post: Markdown Syntax: Formatting Help
 
You
 
© 2013 DaniWeb® LLC
Page generated in 0.0826 seconds using 2.74MB