如何判断SVG路径碰撞点法向量是否需反转以指向图形外部?
判断SVG图形碰撞点法向量是否指向外部的最快方法
我正在用JavaScript开发基于SVG的物理引擎(未采用Canvas顶点方案),已通过以下代码计算出碰撞点的法向量:
let dx = 0.001; let after = a.getPointAtLength(i + dx).matrixTransform(a.getScreenCTM()) let before = a.getPointAtLength(i - dx).matrixTransform(a.getScreenCTM()) arr.push({x: -after.y + before.y, y: after.x - before.x}); // Push normal vector
但需要确保法向量指向图形外部,最快的判断及修正方法如下:
核心思路
利用SVG元素原生的isPointInFill()方法,通过判断法向量方向上的点是否在图形内部,来决定是否反转向量:
- 若测试点在图形内部,说明当前法向量指向内部,需要反转;
- 若测试点在外部,说明法向量方向正确。
实现代码
// 获取碰撞点的屏幕坐标 const currPoint = a.getPointAtLength(i).matrixTransform(a.getScreenCTM()); let dx = 0.001; let after = a.getPointAtLength(i + dx).matrixTransform(a.getScreenCTM()) let before = a.getPointAtLength(i - dx).matrixTransform(a.getScreenCTM()) let normal = {x: -after.y + before.y, y: after.x - before.x}; // 归一化法向量(可选,让偏移距离更可控) const normLen = Math.sqrt(normal.x ** 2 + normal.y ** 2); if (normLen > 0) { normal.x /= normLen; normal.y /= normLen; } // 沿法向量取一个微小偏移的测试点(偏移量可根据图形尺寸调整) const offset = 0.5; const testPoint = new DOMPoint( currPoint.x + normal.x * offset, currPoint.y + normal.y * offset ); // 判断测试点是否在图形填充区域内 if (a.isPointInFill(testPoint)) { // 指向内部,反转法向量 normal.x = -normal.x; normal.y = -normal.y; } arr.push(normal);
方法优势
isPointInFill()是浏览器原生优化的API,性能远高于手动实现射线法或包围盒判断,直接复用浏览器的图形渲染逻辑,代码简洁且可靠。
附不符合预期的法向量示例:
内容的提问来源于stack exchange,提问作者anom907 zat
相关产品推荐
相关产品推荐

