Search code examples
mathcomputational-geometrycoordinate

Detect click in a diamond


I want to detect if I click inside a diamond. The only thing I have are the coordinates of the click (x,y), the center of the diamond (x,y) and the width/height of the diamond.

I found this, but the problem is different. pixel coordinates on diamond


Solution

  • The answer that you linked actually contains everything you need: You can do the "Direct point position check" to detect whether a point is inside the diamond.

    I assume that the diamonds can not be rotated or so, otherwise, the question would have been horribly imprecise.

    Here is an MCVE, implemented in Java/Swing as an example:

    DiamondClickTest

    The relevant part is actually the Diamond#contains method at the bottom, which consists of the 4 lines of code taken from the other answer....

    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Point;
    import java.awt.RenderingHints;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseMotionListener;
    import java.awt.geom.Path2D;
    import java.awt.geom.Point2D;
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.SwingUtilities;
    
    
    public class DiamondClickTest
    {
        public static void main(String[] args)
        {
            SwingUtilities.invokeLater(new Runnable()
            {
                @Override
                public void run()
                {
                    createAndShowGUI();
                }
            });
        }
    
        private static void createAndShowGUI()
        {
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            List<Diamond> diamonds = new ArrayList<Diamond>();
            diamonds.add(new Diamond("A", new Point(100,100), 180, 140));
            diamonds.add(new Diamond("B", new Point(300,100), 110, 160));
            diamonds.add(new Diamond("C", new Point(100,300), 110, 180));
            diamonds.add(new Diamond("D", new Point(300,300), 130, 150));
    
            DiamondClickTestPanel p = new DiamondClickTestPanel(diamonds);
            f.getContentPane().add(p);
    
            f.setSize(400,430);
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
    }
    
    class DiamondClickTestPanel extends JPanel implements MouseMotionListener
    {
        private List<Diamond> diamonds;
        private Diamond highlighedDiamond = null;
    
        DiamondClickTestPanel(List<Diamond> diamonds)
        {
            this.diamonds = diamonds;
            addMouseMotionListener(this);
        }
    
        @Override
        protected void paintComponent(Graphics gr)
        {
            super.paintComponent(gr);
            Graphics2D g = (Graphics2D)gr;
            g.setRenderingHint(
                RenderingHints.KEY_ANTIALIASING, 
                RenderingHints.VALUE_ANTIALIAS_ON);
    
            for (Diamond diamond : diamonds)
            {
                draw(g, diamond);
            }
        }
    
        private void draw(Graphics2D g, Diamond diamond)
        {
            Point2D c = diamond.getCenter();
            double x0 = c.getX() + diamond.getWidth() * 0.5;
            double y0 = c.getY();
            double x1 = c.getX();
            double y1 = c.getY() - diamond.getHeight() * 0.5;
            double x2 = c.getX() - diamond.getWidth() * 0.5;
            double y2 = c.getY();
            double x3 = c.getX();
            double y3 = c.getY() + diamond.getHeight() * 0.5;
    
            Path2D p = new Path2D.Double();
            p.moveTo(x0, y0);
            p.lineTo(x1, y1);
            p.lineTo(x2, y2);
            p.lineTo(x3, y3);
            p.closePath();
    
            if (diamond == highlighedDiamond)
            {
                g.setColor(Color.RED);
                g.fill(p);
            }
            g.setColor(Color.BLACK);
            g.draw(p);
            g.drawString(diamond.getName(), (int)c.getX()-4, (int)c.getY()+8);
        }
    
        @Override
        public void mouseDragged(MouseEvent e)
        {
        }
    
        @Override
        public void mouseMoved(MouseEvent e)
        {
            double x = e.getX();
            double y = e.getY();
            highlighedDiamond = null;
            for (Diamond diamond : diamonds)
            {
                if (diamond.contains(x, y))
                {
                    highlighedDiamond = diamond;
                }
            }
            repaint();
        }
    
    }
    
    class Diamond
    {
        private String name;
        private Point2D center;
        private double width;
        private double height;
    
        Diamond(String name, Point2D center, double width, double height)
        {
            this.name = name;
            this.center = center;
            this.width = width;
            this.height = height;
        }
    
        String getName()
        {
            return name;
        }
        Point2D getCenter()
        {
            return center;
        }
        double getWidth()
        {
            return width;
        }
        double getHeight()
        {
            return height;
        }
    
        boolean contains(double x, double y)
        {
            double dx = Math.abs(x - center.getX());
            double dy = Math.abs(y - center.getY());
            double d = dx / width + dy / height;
            return d <= 0.5;
        }
    }