1

This is an extension to my previous question posted here -- Java Swing GUI for equation 5((θ/β) - cos(2πθ/β))

I have implemented the Java program based on the answers provided in the post an here is my program:

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

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

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

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

    class CosGraph extends JPanel {
        public void paintComponent(Graphics g) {

            int graphHeight = 5; // Declared this to set the height of graph based on the value given here.

            super.paintComponent(g);
            int xBase = 100;
            int top = 100;
            int yScale = 100;
            int xAxis = 360;

            int yBase = top + yScale;

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

            g.setColor(Color.red);

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

            int x, y;


            for (int i = 0; i < 360; i++) {

                x = xBase + i;
                y = yBase - (int) (getValue(i)*graphHeight / maxY * yScale);
                g.drawLine(x, y, x, y);

            }
        }

        private double getValue(int theta) {
            int beta = 45;
            double b = (theta / (double) beta);
            double angle = 2 * Math.PI * (b);
            double c = Math.cos(angle);

            double s = (b - c);
            return s;
        }
    }
}

Now in this program I want to have a variable called graphHeight that helps to increase the height of the graph. If I give the value of the variable as 1 then I can see the output like this:

enter image description here

Now if I try to increase the height to 5 then I get the graph but it is not shown smoothly or continuous curve, I get the output like this:

enter image description here

Can someone please help me how to get the output as smooth continuous curve?

Community
  • 1
  • 1
Chaitanya
  • 15,403
  • 35
  • 96
  • 137
  • 1
    You need to change the interval to a smaller quantity. – Malik Brahimi Jan 21 '15 at 21:34
  • 1
    Simplest: Just f'ing connect the points with lines. – Hovercraft Full Of Eels Jan 21 '15 at 21:35
  • @Hovercraft that wouldn't draw a smooth curve though – GeorgeG Jan 21 '15 at 21:36
  • @GeorgeG: nope it wouldn't, but it could be close, and the more data points, the closer it would get. Another option would be to use the data points to create a List of QuadCurve2D or CubicCurve2D objects. My concern is that he's coming here without showing what he's tried, which is not good for him. The steps should be: 1) identify problem, 2) try to solve problem on own, 3) if this fails, ask for help, **but show results from step 2)**, something he has not done. – Hovercraft Full Of Eels Jan 21 '15 at 21:41
  • @MalikBrahimi, when I changed the increment of i as `i+=0.5` to increase the range of x-axis but the program output is not having any graph. – Chaitanya Jan 21 '15 at 21:43
  • @HovercraftFullOfEels, I am new to Java Swings so finding it difficult how to fix this issue. I tried various options which came to my mind but still facing same issue. Can you please suggest what is the better way to fix this issue? – Chaitanya Jan 21 '15 at 21:47
  • 1
    It would be a paint in the butt, but you could use derivatives to create small tangent lines. – Malik Brahimi Jan 21 '15 at 21:49
  • @MalikBrahimi, can you please point to some example how it can be achieved? – Chaitanya Jan 21 '15 at 21:52
  • If you're interval is small enough, you can use `g.drawLine(x1, y1, x2, y2)` for a seemingly continuous function. – Malik Brahimi Jan 21 '15 at 21:54
  • That's what I've been suggesting all along. – Hovercraft Full Of Eels Jan 21 '15 at 21:56
  • @Chaitanya: regardless of what you try, you should **always** show us your best good faith attempt to solve this. Otherwise you're dumping your work here. – Hovercraft Full Of Eels Jan 21 '15 at 21:56
  • @HovercraftFullOfEels, sir I missed the basic point here, now based on comments here I am able to fix the problem. Thanks a lot – Chaitanya Jan 21 '15 at 22:07
  • 1
    Just using cubic curves for the segments is not feasible, the function then might look nice and smooth, but would simply be "wrong". Increasing the number of points (so that it becomes larger than the number of pixels) is not practical either. I think the most sensible approach is to compute the world x-coordinates for the pixel x-coordinates, and compute the coorresponding y-pixel coordinates for the world-y coordinates. Inserting the function in http://stackoverflow.com/a/21894475/3182664 looks "nice", and is as good as it gets with reasonable effort, I guess. – Marco13 Jan 21 '15 at 22:07
  • @Marco13, the program in your link http://stackoverflow.com/questions/21868284/how-to-create-a-jpanel-for-graphing/21894475#21894475 is really good and the graph is very smooth, I will try to understand the code and use it in my program. Thanks a lot for commenting. – Chaitanya Jan 21 '15 at 22:25

2 Answers2

3

You are drawing a curve using points. You are placing one point at each location on the x axis -- this makes sense to do.

When the graph is small, it looks fine, because the y separation of these points is relatively small. However, as you increase the graph size, this flaw becomes more noticeable.

The solution here is to fill in the vertical space with lines. You have a few options for the exact implementation of this:

  1. Draw a line from [x(i), y(i)] to [x(i+1),y(i+1)] -- this is easy, but may not look the way you want.
  2. Draw a line from [x(i), y(i)] to [x(i),y(i+1)] -- this is still pretty easy, but it won't be quite correct: you're continuing up so that you could be an entire pixel off.
  3. Draw a line from [x(i), y(i)] to [x(i),(y(i)+y(i+1))/2], and then from [x(i+1), (y(i)+y(i+1))/2] to [x(i+1),y(i+1)] -- this is what 1 should do (neglecting anti-aliasing), and will be the most correct of your possible options.

I would suggest number 3. Note that you can implement this with a loop of the form:

        int lastY = yBase - (int) (getValue(0)*graphHeight / maxY * yScale);
        for (int i = 1; i < 360; i++) {

            x = xBase + i;
            y = yBase - (int) (getValue(i)*graphHeight / maxY * yScale);
            g.drawLine(x-1, lastY, x-1, (y+lastY)/2);
            g.drawLine(x, (y+lastY)/2, x, y);

        }

If the one pixel overlap bothers you, you can make it a bit more complex such that the second line starts at +/- 1 pixel (depending on if the function is increasing or decreasing).


Alternatively, you can implement number 3 by manually drawing the line, using a for loop, and basically write a special-case version of Bresenham's line algorithm.

zebediah49
  • 7,467
  • 1
  • 33
  • 50
  • Thanks for the clear explanation, also the program worked after I added the missing line which is `lastY = y` in the for loop in your answer. – Chaitanya Jan 21 '15 at 22:17
0

You use graphHeight to define the y of the next point to be painted with g.drawLine(x, y, x, y);. The distance between drawn points will be related to the graphHeight variable

GeorgeG
  • 362
  • 2
  • 16