與對稱性:用單個(gè)方程描述正六邊形的數(shù)學(xué)原理與工程實(shí)踐)
1. 這篇文章真正要解決的問題當(dāng)你聽到“用一個(gè)方程表示正六邊形”時(shí)第一反應(yīng)是什么是覺得這只是一個(gè)炫技的數(shù)學(xué)游戲還是認(rèn)為它離實(shí)際的編程和圖形學(xué)應(yīng)用很遠(yuǎn)事實(shí)上這個(gè)問題背后隱藏著一個(gè)對開發(fā)者極具價(jià)值的核心思想如何用簡潔、連續(xù)的數(shù)學(xué)表達(dá)式去描述一個(gè)離散、規(guī)則的幾何邊界。這不僅僅是數(shù)學(xué)上的優(yōu)雅更是計(jì)算機(jī)圖形學(xué)、游戲開發(fā)、UI設(shè)計(jì)、乃至物理模擬中經(jīng)常遇到的痛點(diǎn)。比如你想在Shader中繪制一個(gè)六邊形的光暈或者在地圖系統(tǒng)中快速判斷一個(gè)點(diǎn)是否在六邊形蜂窩網(wǎng)格內(nèi)又或者想用參數(shù)方程生成一個(gè)平滑過渡的六邊形輪廓而不是用一堆線段去硬拼。傳統(tǒng)的做法是“頂點(diǎn)連線”定義六個(gè)點(diǎn)的坐標(biāo)然后用lineTo依次連接。這種方法直觀但不夠“數(shù)學(xué)”也不夠靈活。尤其是在需要函數(shù)連續(xù)性、可微性或者進(jìn)行距離場Signed Distance Field, SDF計(jì)算時(shí)頂點(diǎn)法就束手無策了。所以這篇文章要解決的不是讓你去記憶一個(gè)復(fù)雜的“魔法公式”而是深入理解“一個(gè)方程”背后的數(shù)學(xué)原理——極坐標(biāo)與對稱性的結(jié)合。我們將從最基礎(chǔ)的思路出發(fā)一步步推導(dǎo)出那個(gè)簡潔的方程并重點(diǎn)探討它在編程中的實(shí)際應(yīng)用場景、代碼實(shí)現(xiàn)以及你可能遇到的“坑”。讀完本文你將能理解用單個(gè)方程描述正多邊形的通用方法論。掌握正六邊形極坐標(biāo)方程的具體形式和推導(dǎo)過程。在Python、GLSL等環(huán)境中用幾行代碼實(shí)現(xiàn)六邊形的繪制、填充和距離判斷。了解這一技術(shù)在SDF、程序化生成等領(lǐng)域的實(shí)際應(yīng)用。2. 基礎(chǔ)概念與核心原理為什么是極坐標(biāo)在深入方程之前我們必須先統(tǒng)一思想為什么笛卡爾坐標(biāo)系x, y在這里顯得笨拙而極坐標(biāo)系r, θ卻能化繁為簡核心差異在于對稱性的表達(dá)。笛卡爾坐標(biāo)系 (x, y)擅長描述水平和垂直方向的關(guān)系。但對于一個(gè)中心對稱且具有多個(gè)旋轉(zhuǎn)對稱軸的正六邊形其邊界條件需要用分段函數(shù)來表示例如“當(dāng)x在某范圍時(shí)y是某個(gè)線性函數(shù)”會(huì)非常繁瑣。極坐標(biāo)系 (r, θ)用“距離原點(diǎn)的長度r”和“與極軸的夾角θ”來描述點(diǎn)。正六邊形的完美之處在于對于任意一個(gè)方向角θ中心到邊界的距離r(θ)是一個(gè)周期函數(shù)。我們只需要找到這個(gè)周期函數(shù)的具體形式就能用一個(gè)方程r f(θ)描述整個(gè)邊界。正六邊形的對稱性利用正六邊形有6條邊對應(yīng)著6個(gè)相同的扇形區(qū)域。每個(gè)扇形區(qū)域的圓心角是60度π/3弧度。關(guān)鍵在于在這個(gè)扇形區(qū)域內(nèi)邊界即六邊形的邊是一條直線。在極坐標(biāo)系下這條直線的方程可以寫為r d / cos(θ - φ)其中d是原點(diǎn)到這條直線的垂直距離即正六邊形的內(nèi)切圓半徑φ是這條直線法線的方向角。由于對稱性我們只需要研究其中一個(gè)扇形例如 -π/6 ≤ θ ≤ π/6內(nèi)的邊界方程然后通過取模運(yùn)算將θ映射回這個(gè)主區(qū)間就能得到適用于所有θ的、統(tǒng)一的r(θ)表達(dá)式。最終的核心方程先給結(jié)論后文推導(dǎo)描述正六邊形邊界的極坐標(biāo)方程的一種經(jīng)典形式是r(θ) R / cos( arctan( sin(θ) / (cos(θ) - sin(θ)/√3 ) ) )但這個(gè)形式很復(fù)雜。經(jīng)過對稱性化簡后一個(gè)更簡潔、更常用的形式是r(θ) a / cos( θ - (π/3) * floor( (3θ π) / (2π) ) )或者利用取模運(yùn)算將θ轉(zhuǎn)換到主區(qū)間[-π/6, π/6]后方程簡化為一個(gè)非常干凈的形式r(θ) d / cos( θ ) 其中θ mod(θ π/6, π/3) - π/6。別被這些公式嚇到下一章我們將通過幾何圖形一步步拆解你會(huì)看到它如何從清晰的幾何關(guān)系中自然誕生。3. 環(huán)境準(zhǔn)備與前置條件為了驗(yàn)證方程并實(shí)現(xiàn)可視化我們需要一個(gè)簡單的編程環(huán)境。本文將以Python為例因?yàn)樗Z法簡潔庫生態(tài)豐富非常適合做數(shù)學(xué)可視化原型。你也可以將核心數(shù)學(xué)邏輯輕松移植到 JavaScript (Canvas)、C (OpenGL) 或 GLSL (Shader) 中。所需環(huán)境與工具Python 3.8 這是主要的編程語言。NumPy 用于高效的數(shù)組運(yùn)算和數(shù)學(xué)函數(shù)計(jì)算。Matplotlib 用于繪制圖形可視化我們的方程和結(jié)果。Jupyter Notebook (可選) 非常適合交互式探索和分步演示但不是必須的。安裝依賴如果你使用pip作為包管理器可以通過以下命令一鍵安裝所需庫pip install numpy matplotlib對于使用conda的用戶conda install numpy matplotlib驗(yàn)證安裝創(chuàng)建一個(gè)新的Python腳本如hexagon_demo.py輸入以下代碼并運(yùn)行確保環(huán)境配置正確。# hexagon_demo.py - 環(huán)境驗(yàn)證 import numpy as np import matplotlib.pyplot as plt print(NumPy version:, np.__version__) print(Matplotlib version:, plt.matplotlib.__version__) # 生成一個(gè)簡單的正弦波測試?yán)L圖 x np.linspace(0, 2*np.pi, 100) y np.sin(x) plt.plot(x, y) plt.title(Environment Test - Sine Wave) plt.grid(True) plt.show()如果成功彈出一個(gè)顯示正弦波的窗口則說明環(huán)境準(zhǔn)備就緒。4. 核心流程拆解從幾何到方程現(xiàn)在讓我們拋開抽象的公式從一張圖開始一步步構(gòu)建出那個(gè)“神奇”的方程。第1步建立幾何模型假設(shè)我們有一個(gè)中心在原點(diǎn)(0,0)且一個(gè)頂點(diǎn)在正x軸上的正六邊形。設(shè)其外接圓半徑為R頂點(diǎn)到中心的距離內(nèi)切圓半徑為d中心到邊的垂直距離。兩者的關(guān)系是d R * cos(π/6) R * √3 / 2。第2步聚焦一個(gè)扇區(qū)考慮從角度-π/6到π/6即 -30° 到 30°的這個(gè)扇區(qū)。這個(gè)扇區(qū)對應(yīng)的那條邊是垂直的想象一下正六邊形最右邊的那條邊。在這個(gè)扇區(qū)內(nèi)對于給定的角度θ點(diǎn)(r, θ)如果落在六邊形的這條邊上那么它滿足這條邊的直線方程。第3步寫出這條邊的直線方程這條邊我們稱其為邊0的直線方程在笛卡爾坐標(biāo)系下是x d。 將其轉(zhuǎn)換為極坐標(biāo)r * cos(θ) d。 因此在這個(gè)扇區(qū)內(nèi)邊界方程為r d / cos(θ) 其中θ ∈ [-π/6, π/6]。第4步擴(kuò)展到所有扇區(qū)——關(guān)鍵的一步其他五條邊不過是這條邊旋轉(zhuǎn)了k * π/3(k1,2,3,4,5) 角度后的結(jié)果。所以對于任意角度θ我們首先需要知道它屬于哪個(gè)扇區(qū)即對應(yīng)哪條邊。數(shù)學(xué)上這可以通過一個(gè)“取?!辈僮鱽硗瓿?。將全局角度θ“平移”到我們的基準(zhǔn)扇區(qū)[-π/6, π/6]。計(jì)算θ_mod mod(θ π/6, π/3) - π/6。 這個(gè)操作確保了θ_mod始終落在[-π/6, π/6]內(nèi)。那么對于這個(gè)θ_mod它對應(yīng)的邊界點(diǎn)就在“邊0”上其極徑r就是d / cos(θ_mod)。第5步得到統(tǒng)一方程因此描述正六邊形邊界的極坐標(biāo)方程可以寫為r(θ) d / cos( θ_mod )其中θ_mod mod(θ π/6, π/3) - π/6d是內(nèi)切圓半徑。這個(gè)方程的美妙之處在于它用一個(gè)連續(xù)的、周期性的表達(dá)式精確地描述了整個(gè)六邊形的輪廓。mod運(yùn)算巧妙地處理了六邊形的旋轉(zhuǎn)對稱性。5. 完整示例與代碼實(shí)現(xiàn)理解了原理我們立刻用代碼來實(shí)現(xiàn)它。我們將完成三個(gè)任務(wù)1) 繪制六邊形輪廓2) 實(shí)現(xiàn)點(diǎn)與六邊形的包含性檢測3) 生成一個(gè)六邊形的距離場(SDF)圖像。5.1 繪制六邊形輪廓# hexagon_plot.py - 使用極坐標(biāo)方程繪制正六邊形 import numpy as np import matplotlib.pyplot as plt def hexagon_boundary_r(theta, d): 計(jì)算正六邊形邊界上對應(yīng)角度theta的極徑r。 參數(shù): theta: 角度弧度可以是標(biāo)量或數(shù)組。 d: 六邊形的內(nèi)切圓半徑中心到邊的距離。 返回: 極徑 r。 # 關(guān)鍵步驟將theta映射到基準(zhǔn)扇區(qū) [-π/6, π/6] # 使用 np.mod 處理數(shù)組輸入 theta_mod np.mod(theta np.pi/6, np.pi/3) - np.pi/6 # 避免除零cos(theta_mod)在邊界上趨近于0但理論上theta_mod不會(huì)正好等于±π/2 r d / np.cos(theta_mod) return r # 參數(shù)設(shè)置 d 2.0 # 內(nèi)切圓半徑 R d / (np.sqrt(3)/2) # 外接圓半徑用于對比 # 生成角度數(shù)組覆蓋0到2π theta np.linspace(0, 2*np.pi, 1000) # 計(jì)算對應(yīng)的極徑 r hexagon_boundary_r(theta, d) # 將極坐標(biāo)轉(zhuǎn)換為笛卡爾坐標(biāo)以便繪圖 x r * np.cos(theta) y r * np.sin(theta) # 繪制 plt.figure(figsize(8, 8)) plt.plot(x, y, b-, linewidth2, labelPolar Equation: r d / cos(θ\)) # 作為對比用頂點(diǎn)法也畫一個(gè) vertices_theta np.arange(0, 2*np.pi, np.pi/3) # 六個(gè)頂點(diǎn)的角度 vertices_x R * np.cos(vertices_theta) vertices_y R * np.sin(vertices_theta) # 閉合多邊形 vertices_x np.append(vertices_x, vertices_x[0]) vertices_y np.append(vertices_y, vertices_y[0]) plt.plot(vertices_x, vertices_y, r--, linewidth1.5, labelVertex Connection) plt.scatter(vertices_x[:-1], vertices_y[:-1], cred, s50, zorder5) plt.axhline(0, colorgray, linestyle:, alpha0.5) plt.axvline(0, colorgray, linestyle:, alpha0.5) plt.axis(equal) plt.grid(True, alpha0.3) plt.legend() plt.title(fRegular Hexagon (Incircle radius dbextvpl)) plt.xlabel(X) plt.ylabel(Y) plt.show()代碼解釋hexagon_boundary_r函數(shù)是我們的核心實(shí)現(xiàn)直接對應(yīng)推導(dǎo)出的方程。np.mod是取模運(yùn)算它確保了theta_mod始終落在[-π/6, π/6)區(qū)間內(nèi)。我們生成了1000個(gè)采樣點(diǎn)用極坐標(biāo)方程計(jì)算出邊界點(diǎn)并轉(zhuǎn)換為(x, y)繪圖。圖中藍(lán)色實(shí)線是我們的“一個(gè)方程”繪制的輪廓紅色虛線是用傳統(tǒng)頂點(diǎn)連接法繪制的輪廓。兩者完美重合驗(yàn)證了方程的正確性。5.2 點(diǎn)與六邊形的包含性檢測距離場思想在圖形學(xué)中我們經(jīng)常需要判斷一個(gè)點(diǎn)是否在形狀內(nèi)部。利用我們的方程可以非常自然地實(shí)現(xiàn)這一點(diǎn)。思路是計(jì)算點(diǎn)到中心的距離r_point和方向角θ_point然后利用方程計(jì)算該方向角上邊界點(diǎn)的極徑r_boundary。如果r_point r_boundary則點(diǎn)在內(nèi)部或邊界上。# point_in_hexagon.py - 點(diǎn)包含性檢測 def is_point_in_hexagon(point, d, center(0, 0)): 判斷一個(gè)點(diǎn)是否在正六邊形內(nèi)部含邊界。 參數(shù): point: 點(diǎn)的坐標(biāo) (x, y)。 d: 六邊形的內(nèi)切圓半徑。 center: 六邊形中心坐標(biāo)。 返回: True 如果點(diǎn)在內(nèi)部或邊界上否則 False。 x, y point cx, cy center # 計(jì)算相對中心的坐標(biāo) dx, dy x - cx, y - cy # 計(jì)算極坐標(biāo) r_point np.hypot(dx, dy) # 等價(jià)于 sqrt(dx^2 dy^2) theta_point np.arctan2(dy, dx) # 范圍在 [-π, π] # 計(jì)算該方向上的邊界距離 r_boundary hexagon_boundary_r(theta_point, d) return r_point r_boundary 1e-9 # 加上一個(gè)小容差處理浮點(diǎn)誤差 # 測試 test_points [(1.0, 0.0), (0.0, 1.5), (1.5, 1.5), (-1.0, -1.0)] d 2.0 for pt in test_points: inside is_point_in_hexagon(pt, d) print(fPoint {pt} is inside hexagon (dbextvpl)? {inside})輸出示例Point (1.0, 0.0) is inside hexagon (d2.0)? True Point (0.0, 1.5) is inside hexagon (d2.0)? True Point (1.5, 1.5) is inside hexagon (d2.0)? False Point (-1.0, -1.0) is inside hexagon (d2.0)? True5.3 生成六邊形距離場(SDF)圖像距離場是矢量圖形和Shader中的核心技術(shù)。有符號距離函數(shù)(SDF)的值表示點(diǎn)到邊界的最短距離內(nèi)部為負(fù)外部為正。我們可以用類似的思想生成一個(gè)近似SDF圖像。# hexagon_sdf.py - 生成六邊形距離場圖像 def hexagon_sdf_grid(d, grid_size400, plotTrue): 生成一個(gè)二維網(wǎng)格上的六邊形距離場。 距離定義為點(diǎn)到邊界的最近距離內(nèi)部為負(fù)外部為正。 這是一個(gè)近似實(shí)現(xiàn)通過比較點(diǎn)到所有六條邊的距離。 # 創(chuàng)建網(wǎng)格 x np.linspace(-R*1.2, R*1.2, grid_size) y np.linspace(-R*1.2, R*1.2, grid_size) X, Y np.meshgrid(x, y) # 初始化距離為一個(gè)大數(shù) dist np.full_like(X, np.inf) # 六條邊的法線方向單位向量和到原點(diǎn)的距離 # 對于正六邊形邊i的法線角度為 i * π/3 for i in range(6): phi i * np.pi / 3 # 法線角度 nx, ny np.cos(phi), np.sin(phi) # 單位法向量 # 點(diǎn)到這條直線的有符號距離: dot((x,y), n) - d # 因?yàn)樗羞叺皆c(diǎn)的距離都是d d_i X * nx Y * ny - d # 取到所有邊距離的最大值對于凸多邊形內(nèi)部點(diǎn)對所有邊的距離都為負(fù)最大值即最小的“穿透深度” # 外部點(diǎn)則至少對一條邊的距離為正 dist np.minimum(dist, d_i) # 我們記錄到最近邊的有符號距離 # 實(shí)際上對于凸多邊形內(nèi)部的點(diǎn)SDF應(yīng)該是所有“邊距離”中最大的那個(gè)負(fù)值中最大的即最接近0的。 # 更準(zhǔn)確的SDF計(jì)算需要求點(diǎn)到所有邊包括頂點(diǎn)的最短距離這里是一個(gè)簡化版主要展示思想。 # 簡化處理dist目前是到最近邊的有符號距離對于凸多邊形這已經(jīng)是一個(gè)可用的近似SDF。 if plot: plt.figure(figsize(10, 8)) # 繪制距離場等高線 levels np.linspace(-d*0.5, d*0.5, 21) contour plt.contourf(X, Y, dist, levelslevels, cmapRdYlBu, extendboth) plt.colorbar(contour, labelSigned Distance (approx.)) # 繪制六邊形輪廓 theta_contour np.linspace(0, 2*np.pi, 200) r_contour hexagon_boundary_r(theta_contour, d) x_contour r_contour * np.cos(theta_contour) y_contour r_contour * np.sin(theta_contour) plt.plot(x_contour, y_contour, k-, linewidth3, labelHexagon Boundary) plt.axis(equal) plt.title(fApproximate Signed Distance Field of a Hexagon (dbextvpl)) plt.xlabel(X) plt.ylabel(Y) plt.legend() plt.grid(True, alpha0.3) plt.show() return X, Y, dist # 生成并繪圖 X, Y, dist_map hexagon_sdf_grid(d2.0, grid_size200, plotTrue)這段代碼生成了一個(gè)以六邊形邊界為零值線的有符號距離場圖像。藍(lán)色區(qū)域表示內(nèi)部負(fù)距離紅色區(qū)域表示外部正距離。這種表示在Shader中用于實(shí)現(xiàn)平滑的邊緣、描邊、發(fā)光等效果極其高效。6. 運(yùn)行結(jié)果與效果驗(yàn)證運(yùn)行上述三段代碼你應(yīng)該能得到以下輸出和圖形hexagon_plot.py彈出一個(gè)窗口顯示一個(gè)完美的正六邊形。藍(lán)色實(shí)線極坐標(biāo)方程繪制與紅色虛線頂點(diǎn)連接繪制完全重合直觀證明了r d / cos(θ_mod)這個(gè)方程的正確性。圖形應(yīng)中心對稱六個(gè)邊筆直頂點(diǎn)均勻分布在外接圓上。point_in_hexagon.py在控制臺(tái)打印出四個(gè)測試點(diǎn)的判斷結(jié)果。例如點(diǎn)(1.5, 1.5)明顯在六邊形外應(yīng)返回False點(diǎn)(0, 1.5)在內(nèi)部應(yīng)返回True。你可以修改test_points列表加入更多點(diǎn)進(jìn)行驗(yàn)證特別是靠近邊界的點(diǎn)以檢驗(yàn)算法的魯棒性。hexagon_sdf.py彈出一個(gè)彩色等高線圖。圖中六邊形邊界清晰可見是藍(lán)色內(nèi)部和紅色外部的分界線零值線。顏色從邊界向內(nèi)外平滑過渡這正是距離場的特征。你可以觀察邊界等高線圖中dist0的等高線就是六邊形輪廓。內(nèi)部顏色越深藍(lán)表示點(diǎn)越深入六邊形內(nèi)部負(fù)距離絕對值越大。外部顏色越深紅表示點(diǎn)離邊界越遠(yuǎn)正距離越大。如何判斷成功圖形繪制正確無畸形或斷裂。包含性檢測邏輯與肉眼判斷一致。距離場圖像中零值線構(gòu)成一個(gè)清晰的正六邊形。修改參數(shù)d內(nèi)切圓半徑后所有圖形和檢測結(jié)果應(yīng)同步、正確地縮放。如果運(yùn)行失敗第一步應(yīng)檢查導(dǎo)入錯(cuò)誤確認(rèn)numpy和matplotlib已正確安裝。除零錯(cuò)誤在hexagon_boundary_r函數(shù)中理論上cos(theta_mod)不會(huì)為零因?yàn)閠heta_mod在開區(qū)間(-π/6, π/6)內(nèi)。但如果由于浮點(diǎn)誤差導(dǎo)致非常接近可以加一個(gè)極小值防止溢出r d / (np.cos(theta_mod) 1e-12)。圖形不顯示如果使用腳本運(yùn)行確保在代碼末尾有plt.show()。如果在Jupyter中請使用%matplotlib inline魔術(shù)命令。7. 常見問題與排查思路在實(shí)際應(yīng)用這個(gè)方程時(shí)你可能會(huì)遇到一些典型問題。下表列出了常見現(xiàn)象、原因及解決方法。問題現(xiàn)象可能原因排查方式解決方案繪制的圖形不是正六邊形而是扭曲的圓形或其他形狀。1.theta_mod計(jì)算錯(cuò)誤取模運(yùn)算未正確將角度映射到[-π/6, π/6)。2. 使用了錯(cuò)誤的d或R。打印幾個(gè)不同theta值對應(yīng)的theta_mod和r檢查其周期性周期應(yīng)為 π/3和范圍。仔細(xì)檢查theta_mod np.mod(theta np.pi/6, np.pi/3) - np.pi/6這行代碼。確保np.pi/6和np.pi/3的值正確。在邊界附近包含性檢測出現(xiàn)誤判內(nèi)部點(diǎn)被判為外部或反之。浮點(diǎn)數(shù)精度問題。點(diǎn)在數(shù)學(xué)上恰好在邊界上但計(jì)算出的r_point和r_boundary有微小差異。在判斷條件r_point r_boundary中加入一個(gè)微小的容差 (epsilon)。將返回條件改為r_point r_boundary epsilon其中epsilon是一個(gè)很小的正數(shù)如1e-9。當(dāng)theta接近±π/6,±π/2等值時(shí)計(jì)算出的r異常大或出現(xiàn)inf。cos(theta_mod)值非常接近零導(dǎo)致除法結(jié)果趨于無窮大。這是數(shù)學(xué)上的奇點(diǎn)但在我們的離散采樣中由于浮點(diǎn)表示可能不會(huì)正好擊中。檢查theta_mod的值是否絕對接近±π/2這不應(yīng)該發(fā)生。在計(jì)算r時(shí)對分母做一個(gè)保護(hù)r d / (np.cos(theta_mod) 1e-12)?;蛘叽_保你的theta采樣點(diǎn)不會(huì)精確落在理論奇點(diǎn)上。距離場(SDF)圖像在頂點(diǎn)處不光滑有“尖角”。簡化版的SDF計(jì)算只考慮邊在頂點(diǎn)附近不準(zhǔn)確。點(diǎn)到頂點(diǎn)的距離可能小于到最近邊的距離。比較點(diǎn)到六個(gè)頂點(diǎn)的距離和到六條邊的距離取絕對值最小的那個(gè)作為SDF值。實(shí)現(xiàn)更精確的六邊形SDF。正六邊形的精確SDF可以在ShaderToy等資源中找到其核心是坐標(biāo)變換和最大值/最小值操作。代碼在向量化運(yùn)算時(shí)報(bào)錯(cuò)或結(jié)果不對。輸入theta可能是數(shù)組但自定義函數(shù)中的某些操作不支持廣播或維度不匹配。確保所有數(shù)學(xué)運(yùn)算都使用NumPy函數(shù)如np.mod,np.cos它們天然支持?jǐn)?shù)組。避免使用Python內(nèi)置的math模塊函數(shù)。統(tǒng)一使用np.命名空間下的函數(shù)。如果theta是標(biāo)量先將其轉(zhuǎn)換為NumPy數(shù)組或確保函數(shù)能處理標(biāo)量輸入。想繪制一個(gè)旋轉(zhuǎn)或平移后的六邊形。方程描述的是中心在原點(diǎn)、一個(gè)頂點(diǎn)在x軸上的“標(biāo)準(zhǔn)”六邊形。先計(jì)算點(diǎn)在標(biāo)準(zhǔn)六邊形坐標(biāo)系下的相對坐標(biāo)和判斷再進(jìn)行逆變換。旋轉(zhuǎn)在計(jì)算theta_point前先將點(diǎn)坐標(biāo)旋轉(zhuǎn)-rotation_angle。平移先將點(diǎn)坐標(biāo)減去中心點(diǎn)(cx, cy)。兩者可結(jié)合。8. 最佳實(shí)踐與工程建議將數(shù)學(xué)方程轉(zhuǎn)化為穩(wěn)定、高效的代碼需要一些工程上的考量。選擇正確的參數(shù) (dvsR)d(內(nèi)切圓半徑) 在極坐標(biāo)方程r d / cos(θ_mod)中直接使用d最為自然因?yàn)樗苯映霈F(xiàn)在邊界的直線方程里。R(外接圓半徑) 如果你更習(xí)慣用“邊長”或“外徑”來定義六邊形大小記住它們的關(guān)系邊長 Rd R * cos(π/6) R * √3 / 2。在代碼中保存一個(gè)作為主參數(shù)另一個(gè)通過計(jì)算得到避免不一致。性能優(yōu)化向量化與預(yù)計(jì)算向量化 如示例所示使用NumPy對整個(gè)角度數(shù)組theta一次性進(jìn)行計(jì)算比循環(huán)快幾個(gè)數(shù)量級。在GLSL Shader中運(yùn)算也是天然向量化的。預(yù)計(jì)算常數(shù) 將π/6,π/3,√3/2等常數(shù)預(yù)先計(jì)算好避免在循環(huán)或每幀中重復(fù)計(jì)算。# 預(yù)計(jì)算常數(shù) PI np.pi PI_OVER_6 PI / 6 PI_OVER_3 PI / 3 SQRT3_OVER_2 np.sqrt(3) / 2Shader中的實(shí)現(xiàn)在GLSL或HLSL中這個(gè)方程可以寫得非常簡潔高效常用于程序化生成圖形。// GLSL 片段著色器示例繪制一個(gè)正六邊形 float hexagon(vec2 p, float d) { // 將點(diǎn)p的坐標(biāo)轉(zhuǎn)換到60度斜角坐標(biāo)系這是另一種常見優(yōu)化方法 vec2 q abs(p); // 更高效的距離估計(jì)避免三角函數(shù) return max((q.x * 0.5 q.y * 0.8660254), q.x) - d; // 0.8660254 ≈ sin(60°) } // 上述是另一種優(yōu)化后的SDF比極坐標(biāo)形式在GPU上更快。 // 極坐標(biāo)形式在需要基于角度的效果時(shí)仍有其價(jià)值。在Shader中應(yīng)優(yōu)先使用更高效的、基于坐標(biāo)變換和max/min操作的SDF實(shí)現(xiàn)它們避免了耗時(shí)的三角函數(shù)和取模運(yùn)算。擴(kuò)展到正N邊形本文的方法具有普適性。對于正N邊形基準(zhǔn)扇區(qū)的角度范圍是[-π/N, π/N]。邊界方程仍為r d / cos(θ_mod)但其中θ_mod mod(θ π/N, 2π/N) - π/N。d是內(nèi)切圓半徑與外接圓半徑R的關(guān)系為d R * cos(π/N)。處理浮點(diǎn)誤差幾何計(jì)算中浮點(diǎn)誤差無處不在。對于邊界判斷、距離比較等操作永遠(yuǎn)使用容差 (epsilon)。一個(gè)通用的經(jīng)驗(yàn)值是1e-6到1e-9具體取決于你的尺度。EPSILON 1e-9 def is_equal(a, b): return abs(a - b) EPSILON測試用例設(shè)計(jì)為你的六邊形相關(guān)函數(shù)編寫測試特別要覆蓋以下情況原點(diǎn) (一定在內(nèi)部)。各個(gè)頂點(diǎn) (應(yīng)在邊界上)。各條邊的中點(diǎn) (應(yīng)在邊界上)。明顯外部和內(nèi)部的點(diǎn)。旋轉(zhuǎn)和平移后的六邊形。9. 總結(jié)與后續(xù)學(xué)習(xí)方向通過本文的推導(dǎo)與實(shí)踐我們揭開了“一個(gè)方程表示正六邊形”的神秘面紗。其核心不在于記憶公式而在于掌握“利用極坐標(biāo)和對稱性將分段邊界統(tǒng)一為周期函數(shù)”這一強(qiáng)大思想。我們從幾何原理出發(fā)推導(dǎo)出方程r d / cos(θ_mod)并用代碼實(shí)現(xiàn)了繪制、檢測和距離場生成驗(yàn)證了其正確性與實(shí)用性。關(guān)鍵收獲數(shù)學(xué)是工具更是思維極坐標(biāo)是處理旋轉(zhuǎn)對稱圖形的利器。mod運(yùn)算是對稱性在數(shù)學(xué)上的完美體現(xiàn)。從連續(xù)到離散的橋梁這個(gè)方程為我們提供了一種用連續(xù)函數(shù)描述離散多邊形邊界的方法這在程序化生成、Shader編程、碰撞檢測等領(lǐng)域至關(guān)重要。代碼是思想的驗(yàn)證通過Python實(shí)現(xiàn)我們不僅驗(yàn)證了方程更將其變成了可用的工具包含性檢測、SDF。下一步可以探索的方向更高效的SDF 研究正六邊形乃至任意凸多邊形在Shader中絕對精確且高性能的SDF實(shí)現(xiàn)通常涉及將點(diǎn)變換到對稱坐標(biāo)系后取最大值。六邊形網(wǎng)格系統(tǒng) 將單個(gè)六邊形的知識(shí)擴(kuò)展到整個(gè)蜂窩網(wǎng)格。學(xué)習(xí)如何將世界坐標(biāo)(x, y)轉(zhuǎn)換為六邊形網(wǎng)格坐標(biāo)(ax, ay, az)立方體坐標(biāo)以及如何進(jìn)行尋路如A*算法在六邊形網(wǎng)格中的應(yīng)用。擴(kuò)展到3D 思考如何表示一個(gè)正六棱柱或截角八面體一種類似六邊形的3D空間填充形狀。在3D中距離函數(shù)和包含性檢測會(huì)更加復(fù)雜。與其他形狀的結(jié)合 如何用類似的數(shù)學(xué)方法描述正方形、正三角形、星形嘗試推導(dǎo)正N邊形的統(tǒng)一極坐標(biāo)方程。在游戲開發(fā)中的應(yīng)用 實(shí)踐用SDF在Unity Shader Graph或Unreal Material中繪制動(dòng)態(tài)的、可交互的六邊形UI元素或地形塊。建議將本文的代碼保存為模板當(dāng)你需要在項(xiàng)目中快速集成六邊形幾何邏輯時(shí)它可以成為一個(gè)可靠的起點(diǎn)。理解了這個(gè)基礎(chǔ)你就能更從容地應(yīng)對更復(fù)雜的圖形學(xué)和幾何編程挑戰(zhàn)。