John Jiang

          a cup of Java, cheers!
          https://github.com/johnshajiang/blog

             :: 首頁 ::  :: 聯系 :: 聚合  :: 管理 ::
            131 隨筆 :: 1 文章 :: 530 評論 :: 0 Trackbacks
          判定一個點是否在三角形內
          如何判定一個點P是否存在于指定的三角形ABC內,這肯定是一個簡單的問題,本文僅用一個圖形界面程序展示了該問題,有興趣的朋友可以看看。(2008.07.24最后更新)

          在此處使用一種常見且簡便的方法:如果三角形PAB,PAC和PBC的面積之和與三角形ABC的面積相等,即可判定點P在三角形ABC內(包括在三條邊上)
          可知,該方法的關鍵在于如何計算三角形的面積。幸運地是,當知道三角形頂點(A,B和C)的坐標((Ax, Ay),(Bx, By)和(Cx, Cy))之后,即可計算出其面積:
          = |(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(300200));
                  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();
              }
          }

          posted on 2008-07-24 17:02 John Jiang 閱讀(7890) 評論(13)  編輯  收藏 所屬分類: JavaSEJavaSwingGUIAlgorithm原創

          評論

          # re: 判定一個點是否在三角形內(原) 2008-07-24 22:09 qiyadeng
          似乎有更好的方法。  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2008-07-25 13:59 長老
          學過計算機圖形學的都知道, 計算機圖形中判斷一個點是否在一條直線上, 或三角內, 根本不必要像幾何數學中這么精確. 最典型的, 一般都是把點用小正方形表示, 而不是圓, 這樣算法大大簡化了. 所以上面的情況, 也有更簡單好用的算法.  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原)[未登錄] 2008-07-27 10:27 nile black
          樓主至少提出了一種方法  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2008-07-27 20:40 Sha Jiang
          > 學過計算機圖形學的都知道, 計算機圖形中判斷一個點是否在一條直線上,
          > 或三角內, 根本不必要像幾何數學中這么精確.
          我這里就是把它當幾何問題來處理的。

          此處使用的面積法,原理容易理解,也很容易用程序實現。
          還可利用線段PA,PB和PC的"走勢"來做判斷。當然,仍然是基于幾何學 :-)  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2008-10-16 01:08 Fu
          如果已經知道三角形三個頂點的坐標,如何判斷另一點是否在這個三角形內呢?
          謝謝!  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2008-10-16 07:52 Sha Jiang
          > 如果已經知道三角形三個頂點的坐標,如何判斷另一點是否在這個三角形內呢?
          這不正是我的這篇Blog所涉及的內容嘛 :-  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原)[未登錄] 2009-08-21 11:50 zhang
          當一個點與一條邊的距離十分近的時候,該方法不成立!我在實際應用中使用過  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2009-08-21 18:13 Sha Jiang
          > 當一個點與一條邊的距離十分近的時候,該方法不成立!我在實際應用中使用過
          就算移動的點在某條邊上,該方法仍然沒有問題啊。  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2009-11-08 04:49 ucdavis
          http://www.blackpawn.com/texts/pointinpoly/default.html  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2010-01-28 22:54 eee
          三角形ABC,點P。用AB表示從A到B的矢量,用<AB>表示AB/|AB|, 用(X,Y)表示矢量X和矢量Y的內積。如果(<BP>,<BC>)*(<BC>,<BA>)<=(<BP>,<BA>),且(<CP>,<CB>)*(<CB>,<CA>)<=(<CP>,<CA>),則P在三角形ABC內部或在其邊上。  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2010-01-29 01:36 eee
          三角形ABC,點P。用AB表示從A到B的矢量,用<AB>表示AB/|AB|, 用(X,Y)表示矢量X和矢量Y的內積。如果(<BP>,<BC>)*(<BC>,<BA>)<(<BP>,<BA>),且(<BP>,<BA>)*(<BA>,<BC>)<(<BP>,<BC>),且(<CP>,<CA>)*(<CA>,<CB>)<(<CP>,<CB>),則P在三角形ABC內部。【【更正】】  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2011-04-21 15:39 Patronum
          ucdavis給的那個鏈接上的方法只需要12次浮點數乘法,而樓主的方法需要24次浮點數乘法,加法次數也是樓主的方法比較多,所以相對而言,還是采取連接中給的方法比較好,叉積判定法。  回復  更多評論
            

          # re: 判定一個點是否在三角形內(原) 2011-04-21 15:40 Patronum
          不過樓主的方法相對容易理解,這一點必須承認。  回復  更多評論
            

          主站蜘蛛池模板: 鹿泉市| 文昌市| 西昌市| 金寨县| 丹东市| 元朗区| 昌宁县| 图们市| 和田县| 兴隆县| 武穴市| 翁源县| 甘洛县| 申扎县| 武宣县| 荥经县| 大渡口区| 墨脱县| 水富县| 毕节市| 宜春市| 宿松县| 阿拉尔市| 丽江市| 阜阳市| 伊宁市| 琼海市| 梅河口市| 昌都县| 盱眙县| 宜川县| 饶河县| 南川市| 额敏县| 宁化县| 田阳县| 恭城| 依安县| 灌南县| 洛阳市| 揭阳市|