确定一个点是不是在球面的一部分内
Posted
技术标签:
【中文标题】确定一个点是不是在球面的一部分内【英文标题】:Determine if a point is within a section of a sphere surface确定一个点是否在球面的一部分内 【发布时间】:2012-12-17 16:19:40 【问题描述】:您好,我开始使用 Three.js 使用 webGL,我需要检测对球体的点击是否在其表面的某个部分内。
目前我可以检测球体是否被点击并获得点击点的坐标。现在我需要根据来自该球体的一组 3D 点来检测该点击是否在该球体的某个区域(另一个建议是可以的)。
球体在中心点,并且该点被保证在球体的表面上。现在我需要计算它是否只是在一个部分内。有什么建议么?我的问题似乎更数学化。 我也更喜欢一种通用的方式来做到这一点,因为这些部分可能只是一个三角形或者可能是更复杂的图形。
【问题讨论】:
可能相关:How do I check if a longitude/latitude point is within a range of coordinates?。仅在那个问题中,OP 具有纬度/经度,而不是三维空间中的点。但两者之间的转换并不太困难 IIRC。 我希望这个问题的答案在某种程度上取决于您如何定义您尚未描述的部分。 对不起。到目前为止,我的部分是用球体表面上的一组点来描述的,这些点形成随机的形状。 我假设组是有序的(否则问题无法解决)。它有sense吗?也就是说,我们可以指望它是逆时针的(按照数学惯例)吗? 是的。如果它们是随机点,我将无法理解 【参考方案1】:我的第一个想法是将您的 3D 点投影到屏幕坐标上(即从世界坐标到视图坐标,就像在屏幕上绘制形状一样)。这为您提供了与感兴趣的表面相对应的视觉区域。这将是使用您的视图进行的简单 3D 到 2D 投影,然后您可以查看点击位置是否位于 2D 多边形中。
然后我意识到这种方法存在一个问题,即如果您的感兴趣区域绕过球体的背面,它将无法工作。
如果这是一个问题,您将需要沿相机方向构建鼠标单击的投影。如果您使用的是等距相机,这应该是可能的......
【讨论】:
背面问题很容易解决。对点进行背面剔除。相应地剔除跳过点。然后 2d 测试很容易,如果您的光线穿过多边形奇数次穿过您的内部,则射出 2d 光线。这可能效率低下。【参考方案2】:从该点绘制一条(大圆)射线。找到与曲线段最近的交点。当且仅当线段从右到左穿过射线时,该点才在曲线内。
【讨论】:
我不明白这个想法。画一个大圆是什么意思? @HugoAlves,从 P 点到球体另一侧的点画一条弧线。想象一下站在这个点上,然后走到栅栏上(它甚至不必沿着一个大圆圈)。如果栅栏是从右到左的,那么你就在里面。【参考方案3】:一种解决方案是渲染伪彩色图像,其中每个区域都有自己的纹理颜色。然后对图像进行采样,使用 pesudocolor 作为数组索引。 * 出于特殊原因,编码应该将值分散一点。
【讨论】:
【参考方案4】:我已经结束了使用与建议不同的方法。
我正在使用矩阵行列式,其中:(T1, T2, T3) 是形成三角形的点,X 是我想知道它是否在这个三角形内的点,然后我简单地计算 3 个行列式:
d1 = det([T1 T2 X])
d2 = det([T1 X T3])
d3 = det([T1 T2 X])
如果所有行列式的符号相同,则该点位于三角形内部。 现在我根据选择区域形成一个三角形列表,并检查该点是否在这些三角形之一内。
this.Detector.triangleDetector = function(position, triangleArray)
for(var idxString in triangleArray)
var index = parseInt(idxString);
if(this.pointInTriangle(position, triangleArray[index].coords1, triangleArray[index].coords2, triangleArray[index].coords3))
return true;
return false;
函数pointInTriangle(x,t1,t2,t3)
进行行列式验证。
this.Detector.pointInTriangle = function(x,T1,T2,T3)
var array1 = [coord1.x ,coord1.y ,coord1.z];
var array2 = [coord2.x ,coord2.y ,coord2.z];
var array3 = [coord3.x ,coord3.y ,coord3.z];
var zero = 0;
var A = [[zero,zero,zero],[zero,zero,zero],[zero,zero,zero]];
var d1,d2,d3;
A[0][0] = position.x;
A[0][1] = position.y;
A[0][2] = position.z;
A[1][0] = array2[0];
A[1][1] = array2[1];
A[1][2] = array2[2];
A[2][0] = array3[0];
A[2][1] = array3[1];
A[2][2] = array3[2];
d1 = MyMath.determinant(A,3);
A[0][0] = array1[0];
A[0][1] = array1[1];
A[0][2] = array1[2];
A[1][0] = position.x;
A[1][1] = position.y;
A[1][2] = position.z;
d2 = MyMath.determinant(A,3);
A[1][0] = array2[0];
A[1][1] = array2[1];
A[1][2] = array2[2];
A[2][0] = position.x;
A[2][1] = position.y;
A[2][2] = position.z;
d3 = MyMath.determinant(A,3);
if((d1>=0 && d2 >=0 && d3>=0) || (d1<=0 && d2 <=0 && d3<=0))
return true;
return false;
;
【讨论】:
以上是关于确定一个点是不是在球面的一部分内的主要内容,如果未能解决你的问题,请参考以下文章