本文主要是记录一下,选择图形,即点在图形中的基础知识。
三角微元
要判断一个点(比如鼠标点)是否在一个封闭图形中,就是判断点是否在边界内部或者在组成图形的三角形内部。 由于可能有凹多边形,还是判断是否在三角形内比较靠谱。三角形是边数最少的多边形了, 一个图形不管你怎么分割,也不可能分出个两边形。三角形被分割后仍然是三角形。就叫它三角微元
为什么要分割为三角微元,当然是因为不规则的图形没有十分通用的更好的判断方法。
向量三角形
为了便于判断,我们需要给三角形一个方向。这个方向是顺时针还是逆时针不重要,重要的是知道它的方向。
已知向量三角形ACB 的三条边 BA AC BC 总的来说就是顺时针方向,这个方向是顺时针还是逆时针不重要。重要的是知道它有方向。
我们通过判断三角形的每一条边和点的关系,来判断点是否在三角形中。这就是同向法,不过,这种方法只适用于共面的点和三角形。
向量和点之间的关系
这里拿边BA来举例说明。
点P和向量BA其实只有两种关系(除开点在线上这种情况), 要么点在向量的左边,要么点在向量的右边。
这里的左右,是相对于BA方向朝上来说的。 P 和D1, D2的情况是一样的都在右边。这个左右同样不重要。
因为我们现在不关心这个点和其他边的关系,所以是一样的。画出来是为了后续。
点和三角形
我们用点P和边BA组成新的三角形。 那么这个新的三角形同样也有方向,有法向量。
如果新的三角形BAP BAD和原来的三角形BAC 方向相同,那么这个点有可能在三角形内。
点在三角形内的充要条件是,点和三条边组成的三角形都和原本的三角形同向。
只要有有一条边不满足,那么这个点就肯定不在三角形中。
具体的, 画一下 三角形 ACP CBP ,然后想象一下随着点p的移动,这些三角形方向的变化,就知道了。
前面说了,在共面的情况下,可以通过判断点P 是否在三边的同侧。在三维空间中,我们需要更强的约束。
可以通过, 判断点和三边组成的新的三角形的法向量是否同向来判断。 这里的法向量需要单位画,便于计算。 单位向量的点积为1,即为同向。
法向量同向,也就意味着,这四点共面了。 同时也意味着,新的三角形,其绘制方向和原三角形相同。 这就与点和向量的关系联系上了。 所以我们直接判断,新的三个三角形的法向量是否同向,就可以判断,点是否在三角形中 。
叉乘
三角形的方向, 可以确定这个三角形的平面的法向量。在右手坐标系中,叉乘遵循右手螺旋, x轴叉乘y轴得到z轴。四指缠绕的方向就是x轴到y轴, 结果就是大拇指的方向z轴。 我们这里只需要知道方向即可,不关心其他。
所以要判断两个三角形的方向, 只要判断他们的法向量的方向,也就是两条边的叉乘结果。
然后用向量点积的结果的来判断。平行向量的点积, 同向为正,反向为负。
点积公式 a · b = |a|*|b|*cosθ. 0的余弦值是1, 180度的余弦是值1.
代码示例
以下代码使用了three.js的数学库。
import {
Vector3,
} from 'https://unpkg.com/three/build/three.module.js';
const A = new Vector3(-6, 9, -4)
const B = new Vector3(0, 9, 4)
const C = new Vector3(6, 9, -4)
const triangle = [A, B,C]
function inTriangle(M, triangle){
let bool = true
for (let i =0; i< 3;i++){
const j = (i+1)%3
const [a,b] = [triangle[i], triangle[j]]
const ma = a.clone().sub(M)
const ab = b.clone().sub(a)
/* 这种叉乘 相当于把用点和三角形的一条边组成了新的三角形 如果新的三角形的方向和三角形的方向相反 这个点肯定就不在三角形内 */
const d = ma.clone().cross(ab)
const len = d.dot(n)
if(len < 0){
return bool= false
}
}
return bool
}