2014-11-19 7 views
2

다이아몬드를 클릭하면 감지하고 싶습니다. 내가 가진 유일한 것은 클릭의 좌표 (x, y), 다이아몬드의 중심 (x, y) 및 다이아몬드의 너비/높이입니다.다이아몬드에서 클릭 감지

찾았지만 문제가 다릅니다. pixel coordinates on diamond

+0

당신은 충분한 정보를 가지고 있지 않습니다. –

+2

정보가 충분하지 않습니다. 우리는 다이아몬드가 얼마나 큰 지 알지 못합니다 (1 픽셀, 100 픽셀, 1000 픽셀, ...). 우리는 또한 다이아몬드의 크기를 모른다. 높이가 10 : 1이고 높이가 너비 일 수도 있고 회전 된 사각형이 될 수도 있습니다 (너비와 높이의 비율이 1 : 1). 이 정보가 없으면 질문에 대답 할 수 없습니다. – Degustaf

+0

미안하지만, 나는 그걸 가질 수 있다는 것을 잊어 버렸다. – ILoveWaffle

답변

1

링크 된 답변에는 실제로 필요한 모든 것이 들어 있습니다. "직접 점 위치 확인"을 통해 포인트가 다이아몬드 안에 있는지 여부를 확인할 수 있습니다.

다이아몬드는 회전 할 수 없다고 가정합니다. 그렇지 않으면 그 질문은 끔찍하게 부정확했을 것입니다. 여기

는 예를 들어 자바/스윙 구현 MCVE이다

DiamondClickTest

관련 부분은 실제로 찍은 코드의 4 개 라인으로 구성 아래쪽 Diamond#contains 방법이며 당신은 다이아몬드의 중심이있는 경우 다른 대답 ....

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; 
    } 
} 
+0

감사합니다. 게시물 도움과 작업. 나는 네가 마지막 기능에서했던 것처럼했다. 왜 d가 0.5보다 작아야합니까? – ILoveWaffle

+0

"d"는 실제로 앤드류 (Andand)의 답변에 설명 된 것처럼 "반경"입니다. 그러나 너비와 높이는 "직경"(반경의 두 배)입니다. 그것이 <= 0.5'이고 <= 1.0'이 아닌 이유입니다. – Marco13

2

l(1) norm을 기준으로 거리 측정 값을 공식화 할 수 있습니다.이 값은 points of fixed distance from some center point form an axially aligned diamond with vertices equidistant from the center입니다.

이 경우 다이아몬드의 꼭지점이 원점을 기준으로 한 좌표 축에 배치 된 정규형으로 다이아몬드를 배치하려면 적절한 아핀 변환을 적용해야합니다. 이 거리를 r이라고 부르십시오. 원래의 다이아몬드의 형태에 따라, 이것은 (다이아몬드가 원점에 중심 맞춤되지 않은 경우) 이동 (회전 (다이아몬드의 대각선이 축 방향으로 정렬되지 않은 경우)과 스케일링 (대각선 길이가 동일하지 않은 경우) 당신이 적용 할 affine 변환의 기초를 형성하는 연산. 그런 다음이 동일한 아핀 변환을 마우스 클릭에 적용하고 결과 지점의 각 구성 요소의 절대 값을 합산합니다. 이 금액을 d라고 부르십시오. r > d이면 포인트가 다이아몬드 내부에 놓입니다. d > r 포인트가 다이아몬드 외부에 있고, r = d 인 경우 포인트가 다이아몬드 가장자리에 놓입니다.

+1

이것은 완전히 정확하지만 OP의 이점으로 중요한 비트는 "각 구성 요소의 절대 값을 합한 것"이라고 지적하고 싶습니다. 아마도 솔루션을 설명하는 더 짧은 방법은 L1 표준에서 일정한 거리의 곡선이 다이아몬드임을 지적하는 것입니다. –

+0

@RobertDodier : 좋은 지적입니다. 이 단순화를 반영하여 업데이트되었습니다. – andand