1

I am trying to create a GUI using Java Swing for the mathematical equation 5((θ/β) - cos(2πθ/β)).

Initially I started using a simple cosine function and created the GUI and it is working correctly. Here is my program for cosine function:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class SimpleCosWave extends JFrame {
    public SimpleCosWave() {
        setLayout(new BorderLayout());
        add(new CosGraph(), BorderLayout.CENTER);
    }

    public static void main(String[] args) {
        SimpleCosWave frame = new SimpleCosWave();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(600, 600);
        frame.setVisible(true);
        frame.setLocationRelativeTo(null);
        frame.setTitle("SineWave");
    }

    class CosGraph extends JPanel {
        public void paintComponent(Graphics g) {
            int xBase = 100;
            int top = 100; 
            int yScale = 100;
            int xAxis = 360; 

            int yBase = top + yScale;
            int x, y;

            g.drawLine(xBase, top, xBase, top + 2 * yScale);
            g.drawLine(xBase, yBase, xBase + xAxis, yBase);

            g.setColor(Color.red);

            for (int i = 0; i < xAxis; i++) {
                x = xBase + i;
                y =  yBase - (int) Math.cos(Math.toRadians(i)) * yScale;
                g.drawLine(x,y,x,y);
            }
        }
    }
}

This program is working fine and I can get the cos graph on swing GUI.

Now I am trying to extend this program to support the equation - 5((θ/β) - cos(2πθ/β)) where θ ranges from 0 to 360 degrees and value of β is such that it is 0 < β < 360 .

I have changed the above code to calculate the y co-ordinate to support this equation like this:

y =  yBase - getValue(i) * yScale;

here getValue method is:

private int getValue(int theta) {
            int beta = 45;
            double b = (theta/beta);

            double angle = 2*Math.PI*(b);

            double c = Math.cos(angle);

            double result = 5*(b-c);
            return (int)result;
        }

When I do this change then I am not getting any proper graph or wave, instead I am getting a horizontal line.

Can someone please help me where I am doing mistake in this code?

Chaitanya
  • 15,403
  • 35
  • 96
  • 137
  • 1
    When you override paintComponent, the first line of your method must always be `super.paintComponent(g);`. See [Painting in AWT and Swing](http://www.oracle.com/technetwork/java/painting-140037.html) for full details. – VGR Jan 21 '15 at 19:43
  • @VGR, I added the line to my code, but there is no change in the output. – Chaitanya Jan 21 '15 at 19:50
  • 1
    I would recommend stepping through this with a debugger, to see what values `getValue` is actually returning, and what `y` values they're translating into. I'm sure you'll see immediately what's happening. – Dawood ibn Kareem Jan 21 '15 at 19:51

2 Answers2

3

Replace:

double b = (theta/beta);

with

double b = (theta/(double)beta);

and see if this helps.

See How to make the division of 2 ints produce a float instead of another int? for more info.

Community
  • 1
  • 1
Wim Deblauwe
  • 25,113
  • 20
  • 133
  • 211
  • I am still getting same issue – Chaitanya Jan 21 '15 at 19:41
  • `g.drawLine` method takes only `int` so cast is required. – Chaitanya Jan 21 '15 at 19:42
  • But your method declares to return `double` ? – Wim Deblauwe Jan 21 '15 at 19:43
  • This answer is partly correct, but some explanation for why the cast is needed would make it better. – VGR Jan 21 '15 at 19:46
  • @WimDeblauwe, my mistake I updated the question, the method return type is `int` – Chaitanya Jan 21 '15 at 19:47
  • @WimDeblauwe, after type casting `beta` to `double` I can see some different output, but I am not clear if that is the correct result of the equation, because I was expecting a different graph. If possible can you please tell me if there is any site that shows the output for these equations. – Chaitanya Jan 21 '15 at 19:50
  • Wolfram Alpha maybe? http://www.wolframalpha.com/input/?i=5%28%28%CE%B8%2F%CE%B2%29+-+cos%282%CF%80%CE%B8%2F%CE%B2%29%29 – Wim Deblauwe Jan 21 '15 at 19:53
  • 1
    No, the method return type should be `double`. You should only cast back to `int` **after** you multiply the result by `yscale`. – Dawood ibn Kareem Jan 21 '15 at 19:53
  • 2
    So you want `y = (int)(yBase - getValue(i) * yScale);` where `getValue` returns `double` not `int`. This is really important. – Dawood ibn Kareem Jan 21 '15 at 19:54
  • @DavidWallace, after using your equation, I can see some graph in output, but it is not continuous and also going out of range of my Frame. Can you please tell me how can I fix the issue? – Chaitanya Jan 21 '15 at 19:59
  • Yes, take my advice under the question. Step through it with a debugger so you can see exactly what's happening. – Dawood ibn Kareem Jan 21 '15 at 20:00
  • 2
    Remember that the expression that you're calculating is going to get up to almost 45, so if `yscale` is 100 then your graph is going to be 4500 pixels high. You might want to rethink your value of `yscale`. – Dawood ibn Kareem Jan 21 '15 at 20:02
  • @Wim Deblauwe, Thanks for pointing to Wolfram link, but I am trying to see an example for 2D graph, but the graph in Wolfram is difficult to understand. – Chaitanya Jan 21 '15 at 20:07
  • @DavidWallace, Thanks a lot for pointing out where I made mistakes in my code. It would be really helpful if you can point me to some site where I can see how the actual graph looks like so that I can compare my output and see if everything is working correctly. – Chaitanya Jan 21 '15 at 20:43
  • It's just a squiggle added to a steep upwards line. Imagine walking uphill while bouncing a slinky. I'm sure you can get Wolfram Alpha or something to draw it for you if you really can't visualise it. – Dawood ibn Kareem Jan 21 '15 at 20:46
3

As Wim Delauwe points out, when dividing an int by an int, you are doing integer division. For example, 45 / 90 results in an int value of zero . However, 45.0 / 90.0 evaluates to the double value of 0.5. If either operand is a double, the other is coerced to a double, so 45 / 90.0 will also yield 0.5.

Similarly, because your values are in a relatively small range, you should not truncate a value to an integer until you have calculated the exact pixel corresponding to the value, to preserve the precision. Thus, getValue should have a return type of double, and it should return result without casting it.

Then, in your drawing code, you would do the cast:

y = yBase - (int) (getValue(i) * yScale);

However, as David Wallace points out, getValue(i) seems to return values between roughly -5 and +43. Multiplying those values by yScale is going to create a very vertically stretched graph.

You could just hard-code normalization:

y = yBase - (int) (getValue(i) / 43.0 * yScale);

I would opt to calculate the largest y value, and normalize them by that:

double maxY = 0;
for (int i = 0; i < xAxis; i++) {
    maxY = Math.max(maxY, Math.abs(getValue(i)));
}

for (int i = 0; i < xAxis; i++) {
    x = xBase + i;
    y = yBase - (int) (getValue(i) / maxY * yScale);
    g.drawLine(x,y,x,y);
}
VGR
  • 40,506
  • 4
  • 48
  • 63