圖形模塊化3

網格選擇,顧名思義,就是把多邊形變成網格後選擇(此方法只適用於多邊形,若是曲線,我們就得將其分段)。
在這裏插入圖片描述
這樣,網格選擇就分成了兩步:

  1. 將多邊形分解爲多個三角形。
  2. 判斷鼠標點是否在三角形中。

來吧,我們先從最基礎的判斷鼠標點是否在三角形中開始說。

一、網格選擇與三角函數

我們可以用鼠標點和三角形其它頂點的夾角之和來判斷。
在這裏插入圖片描述
點D 在▲ABC 中:
∠ADB+∠BDC+∠CDA=360°

點D 不在▲ABC 中:
∠ADB+∠BDC+∠CDA<360°

接下來我們先說一下一下如何基於三個點計算夾角,如∠mon

先根據三個點畫一個角↓
在這裏插入圖片描述
在這裏插入圖片描述
poly.draw(ctx);

把∠mon 的頂點o 歸零:

m.x-=o.x
m.y-=o.y
n.x-=o.x
n.y-=o.y

根據餘弦定理,可以基於點m乘以點n 的點積,om的長度乘以on 的長度,計算∠mon 的餘弦值
在這裏插入圖片描述
根據反餘弦方法acos() 求∠mon,也就是下面的theta

const theta=Math.acos(cosTheta);

Math.acos() 可以自動把根據餘弦取得的弧度限制在[0,Math.PI]之內。

如果我們使用Math.atan2(y,x),會得到基於x 軸正方向的弧度;

而且y 值爲負的時候,atan2(y,x) 的值也是負數,這是不適合夾角求和的。

至於這裏面涉及的點積公式,這是個純數學的知識,大家先知道其用法即可。

感興趣的同學可以評論區扣1,我後面爲它再起一章:點積公式詳解

我們知道了一個夾角的求法之後,那就可以去求∠ADB+∠BDC+∠CDA 的夾角和了。

其和若小於360°,那就在三角之外,否則在三角之中。

我把這樣的方法封裝在了Vector2d 類裏:
在這裏插入圖片描述
注:0.01 是一個用於容差的數。

電腦對浮點數的運算不是絕對精確的,所以我沒有直接用Math.PI*2===sum來做判斷;

而且是讓鼠標點只要靠近了三角形一定範圍,就算選擇上了。

p1.includedAngleTo(p2,p3) 是求∠p1p2p3 的方法:
在這裏插入圖片描述
p1.includedAngle(p2) 求的是角的頂點歸零後夾角:
在這裏插入圖片描述
dot() 就是點積方法:
在這裏插入圖片描述
length() 是求向量長度的方法
在這裏插入圖片描述
inTriangle() 的使用方法:
在這裏插入圖片描述
若上面的bool爲true,那就說明點在三角形中。

關於判斷判斷點位是否在三角形中的方法我們就說到這。

接下來,我們聊聊:圖形選擇-多邊形網格化

在說多邊形網格化之前,我們先畫個複雜點的多邊形出來。

準備一組用於逆時針繪圖的頂點:
在這裏插入圖片描述
基於這組頂點繪製一個多邊形:
在這裏插入圖片描述
在這裏插入圖片描述

二、圖形選擇的思路解析

接下來,我們就說一下網格化思路:

  1. 先判斷points 中的頂點數量,若等於3,那就直接將這三個點存儲起來。否則,下一步。
  2. 把多邊形裏的第一個點作爲起點
    在這裏插入圖片描述
  3. 從起點連接下下個點,構成一個三角形
    在這裏插入圖片描述
  4. 對上面的三角形做兩個判斷:

三角形是否包含了其它頂點
三角形是否爲凹三角形
在這裏插入圖片描述
若出現上面任何一種情況,就把起點的下一個點做爲起點,執行第1步。

若上面的情況都不存在:

那就把構成這個三角形的頂點存儲起來,把下一個點從points 中刪除,把下下個點做爲起點,執行第1步。
在這裏插入圖片描述
到這裏,網格化的思路就說完了,這是一個遞歸方法,最終效果如下:
在這裏插入圖片描述
接下來,咱們就說一下這整個邏輯中涉及的兩個知識點:

  1. 三角形是否包含了其它頂點。

這個方法我們上一章說過,遍歷其它頂點,逐一判斷即可,在此便不再贅述。

  1. 判斷三角形的凹凸。

首先我們在定點的時候要遵守一個規則,這裏是逆時針定點。

這樣我們在用叉乘的方法求三角形的面積的時候,面積爲正,那就是凹三角形;面積爲負,那就是凸三角形。

求三角形面積的方法:
在這裏插入圖片描述
這個求面積方法用到的是一個叉乘算法。

整體代碼的實現步驟

  1. 繪製多邊形
    在這裏插入圖片描述
  2. 聲明用於存儲三角形的數組triangles[] 和起點

const triangles=[];
let start=0;

  1. 建立網格
    在這裏插入圖片描述
    len 是points 頂點長度

i0,i1,i2 是通過取餘的方法獲取三角形頂點的索引,因爲網格化可能會對points 循環遍歷。

len===3 是如果points 長度爲三,就直接將三角形頂點放到triangles 集合裏;

這也是個終止遞歸的條件,後面points 會不斷刪除三角形的第2個頂點,從而不斷變小。

area>=0||hasOtherPointInTriangle(p0,p1,p2) 便是思路4中的兩個情況:

若滿足其中之一,就把下一個頂點作爲參數,遞歸執行crtMesh(i1) 方法。

若都不滿足,就存儲三角形,衝points 中刪除三角形的第二個頂點,將三角形的第二個頂點作爲起點參數,執行crtMesh(i1) 方法。

好了,整個網格化的實現過程就是這樣。

三、多邊形怎麼選擇

要選擇多邊形的話,那就遍歷triangles裏的三角形即可,鼠標點只要在一個三角形中,那也就在多邊形中了。

最後我把上面的過程進行了封裝,建立了一個Mesh 類:

下滑查看全部代碼
☟☟☟

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
網格實例化和繪製方法:
在這裏插入圖片描述
圖形選擇方法:
在這裏插入圖片描述
效果:
在這裏插入圖片描述
寫 在 最 後

關於圖形選擇的三篇前端乾貨就講到這啦~
需要複習的小夥伴可以隨時去看~

=== 圖形模塊化2:https://blog.csdn.net/qq_30071415/article/details/106895989

=== 圖形模塊化1
https://blog.csdn.net/qq_30071415/article/details/106895394


摘至開課吧前端團隊,閱讀後頗有收穫分享至此,希望對大家有所幫助~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章