1

My goal is to implement a space filling curve in one frame, and in the other the number of each pixel in the frame. In the future, I will need to draw some coordinates in the third frame. My question now is how do I draw the curve in one frame and the pixels in the other. I only get them in the same frame.

Here is the code:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class HilbertCurve extends JPanel {

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            HilbertCurve exemplo1 = new HilbertCurve();
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(exemplo1);
            frame.pack();
            frame.setLocation(100,100);
            frame.setVisible(true);

            JFrame frame1 = new JFrame();
            frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame1.add(exemplo1);
            frame1.pack();
            frame1.setLocation(800, 100);
            frame1.setVisible(true);
        }
    });
}
private SimpleGraphics sg = null;
private int dist0 = 512;
private int dist = dist0;

public HilbertCurve() {
    sg = new SimpleGraphics();
}

@Override
public Dimension getPreferredSize() {
    return new Dimension(520,520);
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);

    int level = 4;
    dist = dist0;
    for (int i = level; i > 0; i--) {
        dist /= 2;
    }
    sg.goToXY(dist / 2, dist / 2);
    Graphics2D g2d = (Graphics2D) g.create();
    hilbertU(g2d, level);
    g2d.dispose();

}


private void hilbertU(Graphics2D g, int level) {
    if (level > 0) {
        hilbertD(g, level - 1);
        sg.lineRel(g, 0, dist);
        hilbertU(g, level - 1);
        sg.lineRel(g, dist, 0);
        hilbertU(g, level - 1);
        sg.lineRel(g, 0, -dist);
        hilbertC(g, level - 1);
    }
}

private void hilbertD(Graphics2D g, int level) {
    if (level > 0) {
        hilbertU(g, level - 1);
        sg.lineRel(g, dist, 0);
        hilbertD(g, level - 1);
        sg.lineRel(g, 0, dist);
        hilbertD(g, level - 1);
        sg.lineRel(g, -dist, 0);
        hilbertA(g, level - 1);
    }
}

private void hilbertC(Graphics2D g, int level) {
    if (level > 0) {
        hilbertA(g, level - 1);
        sg.lineRel(g, -dist, 0);
        hilbertC(g, level - 1);
        sg.lineRel(g, 0, -dist);
        hilbertC(g, level - 1);
        sg.lineRel(g, dist, 0);
        hilbertU(g, level - 1);
    }
}

private void hilbertA(Graphics2D g, int level) {
    if (level > 0) {
        hilbertC(g, level - 1);
        sg.lineRel(g, 0, -dist);
        hilbertA(g, level - 1);
        sg.lineRel(g, -dist, 0);
        hilbertA(g, level - 1);
        sg.lineRel(g, 0, dist);
        hilbertD(g, level - 1);
    }
}

}

And the SimpleGraphics.java class

import java.awt.Graphics2D;

class SimpleGraphics {
    int a = 1;

    private int x = 0, y = 0;

    public SimpleGraphics() {
    }

    public void goToXY(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void lineRel(Graphics2D g, int deltaX, int deltaY) {
        g.drawLine(x, y, x + deltaX, y + deltaY);
        g.drawString(Integer.toString(a++), x+deltaX, y+deltaY);
        x += deltaX;
        y += deltaY;
    }
}

The output is:Output

The out put I want is: enter image description here

  • You need a common model from which both (or all) the frames can draw from, which describes the data. Each from would then be able to represent the mode differently depending on their required implementations. This would mean that you "generation" code will need to change, and instead of drawing the curve, it will need to generate points which can be stored in the model and shared – MadProgrammer Feb 15 '18 at 02:36

1 Answers1

1

Basically speaking, you want to decouple the data from the view. The way in which the data "might" be rendered should be irrelevant to the data.

This concept is commonly know as "Model-View-Controller".

To start with, you want to create a model of your "Hilbert Curve", which would be a bunch of points, each point representing the next point in the curve, for example...

public class HilbertCurveModel {

    private List<Point> points;
    private int distribution;

    private int xDelta, yDelta;

    public HilbertCurveModel(int level, int size) {
        points = new ArrayList<>(25);
        distribution = size;
        for (int i = level; i > 0; i--) {
            distribution /= 2;
        }
        hilbertU(level);
    }

    public int getDistribution() {
        return distribution;
    }

    public List<Point> getPoints() {
        List<Point> copy = new ArrayList<>(points.size());
        for (Point p : points) {
            copy.add(new Point(p));
        }
        return copy;
    }

    protected void addLine(int x, int y) {
        points.add(new Point(x + xDelta, y + yDelta));
        xDelta += x;
        yDelta += y;
    }

    private void hilbertU(int level) {
        if (level > 0) {
            hilbertD(level - 1);
            addLine(0, distribution);
            hilbertU(level - 1);
            addLine(distribution, 0);
            hilbertU(level - 1);
            addLine(0, -distribution);
            hilbertC(level - 1);
        }
    }

    private void hilbertD(int level) {
        if (level > 0) {
            hilbertU(level - 1);
            addLine(distribution, 0);
            hilbertD(level - 1);
            addLine(0, distribution);
            hilbertD(level - 1);
            addLine(-distribution, 0);
            hilbertA(level - 1);
        }
    }

    private void hilbertC(int level) {
        if (level > 0) {
            hilbertA(level - 1);
            addLine(-distribution, 0);
            hilbertC(level - 1);
            addLine(0, -distribution);
            hilbertC(level - 1);
            addLine(distribution, 0);
            hilbertU(level - 1);
        }
    }

    private void hilbertA(int level) {
        if (level > 0) {
            hilbertC(level - 1);
            addLine(0, -distribution);
            hilbertA(level - 1);
            addLine(-distribution, 0);
            hilbertA(level - 1);
            addLine(0, distribution);
            hilbertD(level - 1);
        }
    }

}

Once you have the model, you can share it between views, so that they can render it in what ever way they see fit, for example...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

public class Test {

    public class HilbertCurveModel {

        private List<Point> points;
        private int distribution;

        private int xDelta, yDelta;

        public HilbertCurveModel(int level, int size) {
            points = new ArrayList<>(25);
            distribution = size;
            for (int i = level; i > 0; i--) {
                distribution /= 2;
            }
            hilbertU(level);
        }

        public int getDistribution() {
            return distribution;
        }

        public List<Point> getPoints() {
            List<Point> copy = new ArrayList<>(points.size());
            for (Point p : points) {
                copy.add(new Point(p));
            }
            return copy;
        }

        protected void addLine(int x, int y) {
            points.add(new Point(x + xDelta, y + yDelta));
            xDelta += x;
            yDelta += y;
        }

        private void hilbertU(int level) {
            if (level > 0) {
                hilbertD(level - 1);
                addLine(0, distribution);
                hilbertU(level - 1);
                addLine(distribution, 0);
                hilbertU(level - 1);
                addLine(0, -distribution);
                hilbertC(level - 1);
            }
        }

        private void hilbertD(int level) {
            if (level > 0) {
                hilbertU(level - 1);
                addLine(distribution, 0);
                hilbertD(level - 1);
                addLine(0, distribution);
                hilbertD(level - 1);
                addLine(-distribution, 0);
                hilbertA(level - 1);
            }
        }

        private void hilbertC(int level) {
            if (level > 0) {
                hilbertA(level - 1);
                addLine(-distribution, 0);
                hilbertC(level - 1);
                addLine(0, -distribution);
                hilbertC(level - 1);
                addLine(distribution, 0);
                hilbertU(level - 1);
            }
        }

        private void hilbertA(int level) {
            if (level > 0) {
                hilbertC(level - 1);
                addLine(0, -distribution);
                hilbertA(level - 1);
                addLine(-distribution, 0);
                hilbertA(level - 1);
                addLine(0, distribution);
                hilbertD(level - 1);
            }
        }

    }

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                HilbertCurveModel model = new HilbertCurveModel(4, 512);

                HilbertCurve exemplo1 = new HilbertCurve(model);
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(exemplo1);
                frame.pack();
                frame.setLocation(100, 100);
                frame.setVisible(true);

                // This is the second window ;)

                int xPos = model.getDistribution() / 2;
                int yPos = model.getDistribution() / 2;

                DefaultListModel listModel = new DefaultListModel();
                listModel.addElement(new Point(xPos, yPos));
                for (Point p : model.getPoints()) {
                    listModel.addElement(p);
                }

                JFrame frame1 = new JFrame();
                frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame1.add(new JScrollPane(new JList(listModel)));
                frame1.pack();
                frame1.setLocation(800, 100);
                frame1.setVisible(true);
            }
        });
    }

    public class HilbertCurve extends JPanel {

        private HilbertCurveModel model;
        private int xPos, yPos;

        public HilbertCurve(HilbertCurveModel model) {
            this.model = model;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(520, 520);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int xPos = model.getDistribution() / 2;
            int yPos = model.getDistribution() / 2;

            List<Point> points = model.points;
            if (points.size() == 0) {
                return;
            }
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.translate(xPos, yPos);
            g2d.setColor(Color.BLACK);
            Point from = new Point(0, 0);
            for (Point point : points) {
                Point to = new Point(point);
                System.out.println(from + "x" + to);
                Line2D line = new Line2D.Double(from, to);
                g2d.draw(line);
                from = to;
            }
            g2d.dispose();
        }
    }
}

This will basically create two windows, one will render the curve and the other will display a list of points

Updated

The problem about my code is that I have the g.drawLine(x, y, x + deltaX, y + deltaY); g.drawString(Integer.toString(a++), x+deltaX, y+deltaY); in the lineRel method, and I don't know how to draw differently in another frame. Every time I call the paint method, it draws the same thing

Okay, this example goes to the nth degree. Personally, I'd have created a renderer which contained a couple of flags which could be used to turn features on or off, but this demonstrates inheritance and how you might be able to use to use it to expand the functionality of a class.

Curvy

import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.geom.Line2D;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Test {

    public class HilbertCurveModel {

        private List<Point> points;
        private int distribution;

        private int xDelta, yDelta;

        public HilbertCurveModel(int level, int size) {
            points = new ArrayList<>(25);
            distribution = size;
            for (int i = level; i > 0; i--) {
                distribution /= 2;
            }
            hilbertU(level);
        }

        public int getDistribution() {
            return distribution;
        }

        public List<Point> getPoints() {
            List<Point> copy = new ArrayList<>(points.size());
            for (Point p : points) {
                copy.add(new Point(p));
            }
            return copy;
        }

        protected void addLine(int x, int y) {
            points.add(new Point(x + xDelta, y + yDelta));
            xDelta += x;
            yDelta += y;
        }

        private void hilbertU(int level) {
            if (level > 0) {
                hilbertD(level - 1);
                addLine(0, distribution);
                hilbertU(level - 1);
                addLine(distribution, 0);
                hilbertU(level - 1);
                addLine(0, -distribution);
                hilbertC(level - 1);
            }
        }

        private void hilbertD(int level) {
            if (level > 0) {
                hilbertU(level - 1);
                addLine(distribution, 0);
                hilbertD(level - 1);
                addLine(0, distribution);
                hilbertD(level - 1);
                addLine(-distribution, 0);
                hilbertA(level - 1);
            }
        }

        private void hilbertC(int level) {
            if (level > 0) {
                hilbertA(level - 1);
                addLine(-distribution, 0);
                hilbertC(level - 1);
                addLine(0, -distribution);
                hilbertC(level - 1);
                addLine(distribution, 0);
                hilbertU(level - 1);
            }
        }

        private void hilbertA(int level) {
            if (level > 0) {
                hilbertC(level - 1);
                addLine(0, -distribution);
                hilbertA(level - 1);
                addLine(-distribution, 0);
                hilbertA(level - 1);
                addLine(0, distribution);
                hilbertD(level - 1);
            }
        }

    }

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                HilbertCurveModel model = new HilbertCurveModel(4, 512);

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new HilbertCurveLineRenderer(model));
                frame.pack();
                frame.setLocation(100, 100);
                frame.setVisible(true);

                JFrame frame2 = new JFrame();
                frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame2.add(new HilbertCurveLineAndPointRenderer(model));
                frame2.pack();
                frame2.setLocation(100 + frame.getWidth(), 100);
                frame2.setVisible(true);
            }
        });
    }

    public abstract class AbstractHilbertCurve extends JPanel {

        private HilbertCurveModel model;

        public AbstractHilbertCurve(HilbertCurveModel model) {
            this.model = model;
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(520, 520);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int xPos = model.getDistribution() / 2;
            int yPos = model.getDistribution() / 2;

            List<Point> points = model.points;
            if (points.size() == 0) {
                return;
            }
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.translate(xPos, yPos);
            g2d.setColor(Color.BLACK);
            Point from = new Point(0, 0);
            int count = 0;
            for (Point to : points) {
                count++;
                // I don't trust you to play nice with my graphics context
                Graphics2D copyG = (Graphics2D) g2d.create();
                renderLine(copyG, from, to);
                renderCurrentPoint(copyG, count, to);
                from = to;
                copyG.dispose();
            }
            g2d.dispose();
        }

        protected void renderLine(Graphics2D g2d, Point from, Point to) {
        }

        protected void renderCurrentPoint(Graphics2D g2d, int count, Point current) {
        }
    }

    public class HilbertCurveLineRenderer extends AbstractHilbertCurve {

        public HilbertCurveLineRenderer(HilbertCurveModel model) {
            super(model);
        }

        protected void renderLine(Graphics2D g2d, Point from, Point to) {
            Line2D line = new Line2D.Double(from, to);
            g2d.draw(line);
        }
    }

    public class HilbertCurveLineAndPointRenderer extends AbstractHilbertCurve {

        public HilbertCurveLineAndPointRenderer(HilbertCurveModel model) {
            super(model);
        }

        protected void renderLine(Graphics2D g2d, Point from, Point to) {
            Line2D line = new Line2D.Double(from, to);
            g2d.draw(line);
        }

        @Override
        protected void renderCurrentPoint(Graphics2D g2d, int count, Point current) {
            String text = Integer.toString(count);
            FontMetrics fm = g2d.getFontMetrics();
            int x = current.x - (fm.stringWidth(text) / 2); 
            g2d.drawString(text, x, current.y);
        }

    }
}

I would, highly, recommend you take a closer look at How to perform custom painting and Painting in Swing to gain a better understanding into how painting actually works in Swing.

Also, an instance of a component can only reside in one container at a time. As demonstrated in the above example, you will need at least two instances of the render pane

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Thank you for your time man, I am a little confused on the code. Honestly, you helped a lot. So, when I meant how to draw the points, I meant like in the map. I am going to post the picture of the output I am looking for. I tried doing it myself, but if I do it in your code, it erases the Hilbert's curve one, and I need both the curve and the points. – Ian Tupiara Feb 15 '18 at 04:21
  • Yeah, I have the line that does that. But I don't know how to do it in a different frame – Ian Tupiara Feb 15 '18 at 04:28
  • Okay. So the example separates the data from the view. I've provided one view which renders just the line. You could copy (but I'd work up a extensions point) which can render both the line AND the points – MadProgrammer Feb 15 '18 at 04:31
  • The problem about my code is that I have the g.drawLine(x, y, x + deltaX, y + deltaY); g.drawString(Integer.toString(a++), x+deltaX, y+deltaY); in the lineRel method, and I don't know how to draw differently in another frame. Every time I call the paint method, it draws the same thing. – Ian Tupiara Feb 15 '18 at 04:32
  • @IanTupiara You seem to have a basic misunderstanding of basic OO concepts which isn't helping you solve what is essentially a "not" basic problem – MadProgrammer Feb 15 '18 at 04:50
  • Thank you man, the HilbertCurveLineRenderer and the HilbertCurveAndLineRenderer was what I was trying to write, but didn't know how to. You're a beast man! Thank you for the patience. – Ian Tupiara Feb 15 '18 at 05:24
  • `HilbertCurveLineAndPointRenderer` could extend from `HilbertCurveLineRenderer` and it wouldn't need to re-implement the `renderLine` method, but I thought that might be pushing you just little to hard ;) – MadProgrammer Feb 15 '18 at 05:26
  • I would probably understand it if I looked into it for an hour, but I would never be able to write it with the extend. I couldn't even write it without it. Thank you for your help again man, this is the 2nd time you come in clutch! – Ian Tupiara Feb 15 '18 at 05:30
  • Is there a way I could divide this program into different class files, so I could understand the code better. – Ian Tupiara Feb 17 '18 at 17:26
  • hey, could you help me with my last question? [Question](https://stackoverflow.com/questions/48979775/hilbert-curve-in-applet-with-matrix-of-coordinates) – Ian Tupiara Feb 26 '18 at 02:36