Flipping shape (not image)

2019-01-28 13:42发布

问题:

Solved: Thanks @MadProgrammer

I replaced g2.rotate(Math.toRadians(180.0)); by g2.scale(1, -1); thanks^^


I wrote program to show Digital Clock with mirror (Vertical Flip)

This is my code

    import java.awt.*;
    import java.awt.font.GlyphVector;
    import javax.swing.*;
    import java.util.*;

    public class DigitalClock extends JFrame implements Runnable {
        /**
         * @author HASSAN
         */
        Thread runner; // declare global objects
        Font clockFont;
        Shape mirror;

        public DigitalClock() {
            super("Digital Clock - Hassan Sharaf 12MCMB33");
            setSize(600, 500);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
            setResizable(false); // create window
            setLocationRelativeTo(null);
            clockFont = new Font("digifacewide", Font.BOLD, 100); // create font

            Container contentArea = getContentPane();
            ClockPanel timeDisplay = new ClockPanel();
            contentArea.add(timeDisplay); // add components
            setContentPane(contentArea);
            start(); // start thread running
        }

        public class ClockPanel extends JPanel {

            public void paintComponent(Graphics painter) {
                // super.paintComponent(painter);
                Graphics2D g2 = (Graphics2D) painter;
                g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                g2.setFont(clockFont); // create clock components
                g2.setColor(Color.black);
                g2.drawString(timeNow(), 20, 140);
                GlyphVector v = clockFont.createGlyphVector(getFontMetrics(clockFont).getFontRenderContext(), timeNow());
                mirror = v.getOutline();
                g2.translate(553, 160);
                g2.rotate(Math.toRadians(180.0));   
                g2.fill(mirror);
                        g2.draw(mirror);

            }
        }

        // get current time
        public String timeNow() {
            Calendar now = Calendar.getInstance();
            int hrs = now.get(Calendar.HOUR_OF_DAY);
            int min = now.get(Calendar.MINUTE);
            int sec = now.get(Calendar.SECOND);
            String time = zero(hrs) + ":" + zero(min) + ":" + zero(sec);
            return time;
        }

        public String zero(int num) {
            String number = (num < 10) ? ("0" + num) : ("" + num);
            return number; // Add leading zero if needed
        }

        public void start() {
            if (runner == null) {
                runner = new Thread(this);
            }
            runner.start();
            // method to start thread
        }

        public void run() {
            while (runner == Thread.currentThread()) {
                repaint();
                // define thread task
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println("Thread failed");
                }
            }
        }

        // create main method
        public static void main(String[] args) {
            DigitalClock clock = new DigitalClock();
        }
    }

Problem: I used rotate() method, but actually I don't want rotate the clock I want flip it vertically Question: How can I flip the shape (not image)?

回答1:

You have lots-o-choices depending on what you want to achieve...

You can...

  • Create a PathIterator from the shape object, using a AffineTransform matching your rotational requirements. This will require you to create a new path, appending the PathIterator to it so you can paint it ... or
  • Create a new Path2D using the shape to be rotated as the base for the new path and passing the AffineTransform to it. This is pretty much the same as the first option, but requires less code...

Here's an example....

public class SpinningTriangle {

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

    public SpinningTriangle() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new SpinPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class SpinPane extends JPanel {

        private Triangle triangle;
        private float angle = 0;

        public SpinPane() {
            triangle = new Triangle(50, 100);
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    angle += 2;
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            Rectangle bounds = triangle.getBounds();
//            PathIterator pi = triangle.getPathIterator(AffineTransform.getRotateInstance(Math.toRadians(angle), bounds.width / 2, bounds.height / 2));
//            Path2D path = new Path2D.Float();
//            path.append(pi, true);
            Path2D path = new Path2D.Float(triangle, AffineTransform.getRotateInstance(Math.toRadians(angle), bounds.width / 2, bounds.height / 2));
            int x = (getWidth() - bounds.width) / 2;
            int y = (getHeight() - bounds.height) / 2;
            g2d.translate(x, y);
            g2d.setColor(Color.RED);
            g2d.fill(path);
            g2d.setColor(Color.YELLOW);
            g2d.draw(path);
            g2d.dispose();
        }

    }

    public class Triangle extends Path2D.Float {

        public Triangle(int width, int height) {

            moveTo(width / 2f, 0);
            lineTo(width, height);
            lineTo(0, height);
            closePath();

        }

    }

}

UPDATED

If all you want to do is "mirror" the shape, you can scale the axis by -1...

public class SpinningTriangle {

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

    public SpinningTriangle() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new FlipPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class FlipPane extends JPanel {

        private Triangle triangle;
        private boolean flip;

        public FlipPane() {
            triangle = new Triangle(50, 100);
            Timer timer = new Timer(500, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    flip = !flip;
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            Rectangle bounds = triangle.getBounds();

            double scale = 1 * (flip ? -1 : 1);

            Path2D path = new Path2D.Float(triangle, AffineTransform.getScaleInstance(scale, scale));
            int x = (getWidth() - bounds.width) / 2;
            int y = (getHeight() - bounds.height) / 2;
            if (flip) {

                y += bounds.height;
                x += bounds.width;

            }
            g2d.translate(x, y);
            g2d.setColor(Color.RED);
            g2d.fill(path);
            g2d.setColor(Color.YELLOW);
            g2d.draw(path);
            g2d.dispose();
        }

    }

    public class Triangle extends Path2D.Float {

        public Triangle(int width, int height) {

            moveTo(width / 2f, 0);
            lineTo(width, height);
            lineTo(0, height);
            closePath();

        }

    }

}