大家好,我是前端西瓜哥。
開發圖形編輯器,你會經常要解決一些算法問題。本文盤點一些我開發圖形編輯器時常用到的簡單幾何算法。
判斷兩個矩形是否發生碰撞(或者說相交),即兩個矩形有重合的區域。
常見使用場景:
使用選擇工具框選圖形(框選策略除了相交,還可以用相交或其他方案)。
遍歷圖形,通過判斷視口矩形和圖形包圍盒的矩形碰撞,剔除掉視口外的圖形渲染操作,提高性能。
export function isRectIntersect2(rect1: IBox2, rect2: IBox2) { return ( rect1.minX <= rect2.maxX && rect1.maxX >= rect2.minX && rect1.minY <= rect2.maxY && rect1.maxY >= rect2.minY );}
關于 IBox2 為包圍盒的接口簽名:
interface IBox2 { minX: number; minY: number; maxX: number; maxY: number;}
該算法用于判斷矩形 1 是否包含矩形 2。
常見使用場景:
使用選擇工具框選圖形(這次用的是包含策略);
function isRectContain2(rect1: IBox2, rect2: IBox2) { return ( rect1.minX <= rect2.minX && rect1.minY <= rect2.minY && rect1.maxX >= rect2.maxX && rect1.maxY >= rect2.maxY );}
對圖形旋轉,是一個非常基礎的功能。計算旋轉后的點是很常見的需求。
常見使用場景:
用到三角函數算法。
const transformRotate = ( x: number, y: number, radian: number, cx: number, cy: number,) => { if (!radian) { return { x, y }; } const cos = Math.cos(radian); const sin = Math.sin(radian); return { x: (x - cx) * cos - (y - cy) * sin + cx, y: (x - cx) * sin + (y - cy) * cos + cy, };}
常見使用場景:
用于實現圖形拾取,判斷矩形圖形或包圍盒是否在光標位置上。
function isPointInRect(point: IPoint, rect: IRect) { return ( point.x >= rect.x && point.y >= rect.y && point.x <= rect.x + rect.width && point.y <= rect.y + rect.height );}
選中多個矩形時,要計算它們組成的大矩形,然后繪制出大選中框。
function getRectsBBox(...rects: IRect[]): IBox { if (rects.length === 0) { throw new Error('the count of rect can not be 0'); } const minX = Math.min(...rects.map((rect) => rect.x)); const minY = Math.min(...rects.map((rect) => rect.y)); const maxX = Math.max(...rects.map((rect) => rect.x + rect.width)); const maxY = Math.max(...rects.map((rect) => rect.y + rect.height)); return { x: minX, y: minY, width: maxX - minX, height: maxY - minY, };}
這里用的是另一種包圍盒子的表達,所以多了一層轉換。
interface IRect = { x: number; y: number; width: number; height: number;}type IBox = IRect
通過旋轉控制點旋轉圖形時,需要通過向量的點積公式來計算移動的夾角,去更新圖形的旋轉角度。
計算 [x - cx, y - cy] 和 [0, -1] 兩個向量夾角的算法實現:
/** * 求向量到右側軸(x正半軸)的夾角 * 范圍在 [0, Math.PI * 2) */export function calcVectorRadian(cx: number, cy: number, x: number, y: number) { const a = [x - cx, y - cy]; const b = [0, -1]; const dotProduct = a[0] * b[0] + a[1] * b[1]; const d = Math.sqrt(a[0] * a[0] + a[1] * a[1]) * Math.sqrt(b[0] * b[0] + b[1] * b[1]); let radian = Math.acos(dotProduct / d); if (x < cx) { radian = Math.PI * 2 - radian; } return radian;}
做圖形編輯器,經常要和幾何算法打交道,各種相交判斷、居中計算、光標縮放、找最近的參照線等等。
這對算法能力有一定要求的,建議多去刷刷 leetcode。此外就是多畫圖分析。
在開發中,我們還要自己去分析需求,結合圖形編輯器的具體實現,抽離出算法問題,并配合合適的數據結構,去解題。解法可能一次不是最優解, 但我們可以慢慢迭代,慢慢優化的。
雖然有點耗腦細胞,但最后把難題解決,還是非常有成就感。
本文鏈接:http://www.www897cc.com/showinfo-26-5160-0.html圖形編輯器開發:一些會用到的簡單幾何算法
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: VasDolly服務端打渠道包教程