判定一个点是否在三角形内
如何判定一个点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;
}
// 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 ;
}
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 );
}
}
};
}
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();
}
}
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();
}
}
还可参见一篇英文文章: http://www.blackpawn.com/texts/pointinpoly/default.html 好文章 ;-)