判定一个点是否在三角形内
如何判定一个点P是否存在于指定的三角形ABC内,这肯定是一个简单的问题,本文仅用一个图形界面程序展示了该问题,有兴趣的朋友可以看看。(2008.07.24最后更新)
在此处使用一种常见且简便的方法:如果三角形PAB,PAC和PBC的面积之和与三角形ABC的面积相等,即可判定点P在三角形ABC内(包括在三条边上)。
可知,该方法的关键在于如何计算三角形的面积。幸运地是,当知道三角形顶点(A,B和C)的坐标((Ax, Ay),(Bx, By)和(Cx, Cy))之后,即可计算出其面积:
S = |(Ax * By + Bx * Cy + Cx * Zy - Ay * Bx - By * Cx - Cy * Ax) / 2|
关键的代码如下,
// 由给定的三个顶点的坐标,计算三角形面积。
// Point(java.awt.Point)代表点的坐标。
private static double triangleArea(Point pos1, Point pos2, Point pos3) {
double result = Math.abs((pos1.x * pos2.y + pos2.x * pos3.y + pos3.x * pos1.y
- pos2.x * pos1.y - pos3.x * pos2.y - pos1.x * pos3.y) / 2.0D);
return result;
}
// 判断点pos是否在指定的三角形内。
private static boolean inTriangle(Point pos, Point posA, Point posB,
Point posC) {
double triangleArea = triangleArea(posA, posB, posC);
double area = triangleArea(pos, posA, posB);
area += triangleArea(pos, posA, posC);
area += triangleArea(pos, posB, posC);
double epsilon = 0.0001; // 由于浮点数的计算存在着误差,故指定一个足够小的数,用于判定两个面积是否(近似)相等。
if (Math.abs(triangleArea - area) < epsilon) {
return true;
}
return false;
}
执行该应用程序,用鼠标在其中点击三次,即可绘制一个三角形,如下组图所示:
然后仅需移动鼠标,就会出现一个空心圆圈。如果圆圈的中心在三角内(包含在三条边上),则圆圈显示为红色;否则,显示为蓝色。如下组图所示:
完整代码如下:
public class CanvasPanel extends JPanel {
private static final long serialVersionUID = -6665936180725885346L;
private Point firstPoint = null;
private Point secondPoint = null;
private Point thirdPoint = null;
public CanvasPanel() {
setBackground(Color.WHITE);
addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawTriangel(g);
}
private void drawTriangel(Graphics g) {
if (firstPoint != null && secondPoint != null) {
g.drawLine(firstPoint.x, firstPoint.y, secondPoint.x, secondPoint.y);
if (thirdPoint != null) {
g.drawLine(firstPoint.x, firstPoint.y, thirdPoint.x, thirdPoint.y);
g.drawLine(secondPoint.x, secondPoint.y, thirdPoint.x, thirdPoint.y);
}
}
}
private static boolean inTriangle(Point pos, Point posA, Point posB,
Point posC) {
double triangeArea = triangleArea(posA, posB, posC);
double area = triangleArea(pos, posA, posB);
area += triangleArea(pos, posA, posC);
area += triangleArea(pos, posB, posC);
double epsilon = 0.0001;
if (Math.abs(triangeArea - area) < epsilon) {
return true;
}
return false;
}
private static double triangleArea(Point pos1, Point pos2, Point pos3) {
double result = Math.abs((pos1.x * pos2.y + pos2.x * pos3.y + pos3.x * pos1.y
- pos2.x * pos1.y - pos3.x * pos2.y - pos1.x * pos3.y) / 2.0D);
return result;
}
private MouseInputAdapter mouseAdapter = new MouseInputAdapter() {
public void mouseReleased(MouseEvent e) {
Point pos = e.getPoint();
if (firstPoint == null) {
firstPoint = pos;
} else if (secondPoint == null) {
secondPoint = pos;
Graphics g = CanvasPanel.this.getGraphics();
CanvasPanel.this.paintComponent(g);
g.drawLine(firstPoint.x, firstPoint.y, secondPoint.x, secondPoint.y);
} else if (thirdPoint == null) {
thirdPoint = pos;
Graphics g = CanvasPanel.this.getGraphics();
CanvasPanel.this.paintComponent(g);
g.drawLine(firstPoint.x, firstPoint.y, secondPoint.x, secondPoint.y);
g.drawLine(firstPoint.x, firstPoint.y, thirdPoint.x, thirdPoint.y);
g.drawLine(secondPoint.x, secondPoint.y, thirdPoint.x, thirdPoint.y);
}
}
public void mouseMoved(MouseEvent e) {
Point pos = e.getPoint();
Graphics2D g2 = (Graphics2D) CanvasPanel.this.getGraphics();
CanvasPanel.this.paintComponent(g2);
if (firstPoint != null && secondPoint == null) {
g2.drawLine(firstPoint.x, firstPoint.y, pos.x, pos.y);
} else if (firstPoint != null && secondPoint != null && thirdPoint == null) {
g2.drawLine(firstPoint.x, firstPoint.y, pos.x, pos.y);
g2.drawLine(secondPoint.x, secondPoint.y, pos.x, pos.y);
} else if (firstPoint != null && secondPoint != null && thirdPoint != null) {
if (inTriangle(pos, firstPoint, secondPoint, thirdPoint)) {
g2.setColor(Color.RED);
} else {
g2.setColor(Color.BLUE);
}
int radius = 4;
g2.drawOval(pos.x - radius, pos.y - radius, radius * 2, radius * 2);
}
}
};
}
public class Triangle extends JFrame {
private static final long serialVersionUID = 1L;
private CanvasPanel mainPanel = null;
public Triangle() {
setTitle("Triangle");
setSize(new Dimension(300, 200));
setResizable(false);
init();
Container container = getContentPane();
container.add(mainPanel);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private void init() {
mainPanel = new CanvasPanel();
}
public static void main(String[] args) {
new Triangle();
}
}