可以检查点是否在仅具有整数运算的扇区内以及加法,减法和乘法的基本运算。
对于一个点在一个内部 循环部门 ,它必须满足以下测试:
它必须比扇形半径更接近圆心。
的起始“臂”逆时针定位
要测试向量v2是否顺时针到另一个向量v1,请执行以下操作:
找逆时针 法向量 v1。法向量与原始向量成90度角。这是 直截了当 :如果 v1=(x1,y1) ,那么逆时针正常就是 n1=(-y1,x1) 。
v1=(x1,y1)
n1=(-y1,x1)
找到正常情况下v2投影的大小。这可以通过计算来完成 点积 v2和正常。
projection = v2.x*n1.x + v2.y*n1.y
如果投影是正数,则v2逆时针定位到v1。否则,v2顺时针旋转到v1。
这是一个逆时针的例子:
顺时针的例子:
这些步骤可以合并:
function areClockwise(v1, v2) { return -v1.x*v2.y + v1.y*v2.x > 0; }
半径测试很简单。只需检查点距圆心的距离是否小于所需半径。为了避免计算平方根,我们可以将距离的平方与半径的平方进行比较。
function isWithinRadius(v, radiusSquared) { return v.x*v.x + v.y*v.y <= radiusSquared; }
完整的扇区测试看起来像:
function isInsideSector(point, center, sectorStart, sectorEnd, radiusSquared) { var relPoint = { x: point.x - center.x, y: point.y - center.y }; return !areClockwise(sectorStart, relPoint) && areClockwise(sectorEnd, relPoint) && isWithinRadius(relPoint, radiusSquared); }
以下示例页面展示了几千个点。您可以在以下位置试验代码: http://jsbin.com/oriyes/8/edit 。
<!DOCTYPE html> <html> <head> <script src="http://code.jquery.com/jquery-1.8.2.min.js"></script> <style> .canvas { position: absolute; background: #f4f4f4; border: 8px solid #f4f4f4; width: 400px; height: 400px; } .dot { position: absolute; font: 16px Arial; } .out { color: #ddd; } .in { color: #00dd44; } </style> <script> function isInsideSector(point, center, sectorStart, sectorEnd, radiusSquared) { var relPoint = { x: point.x - center.x, y: point.y - center.y }; return !areClockwise(sectorStart, relPoint) && areClockwise(sectorEnd, relPoint) && isWithinRadius(relPoint, radiusSquared); } function areClockwise(v1, v2) { return -v1.x*v2.y + v1.y*v2.x > 0; } function isWithinRadius(v, radiusSquared) { return v.x*v.x + v.y*v.y <= radiusSquared; } $(function() { var $canvas = $("#canvas"); var canvasSize = 400; var count = 4000; // define the sector var center = { x: canvasSize / 2, y: canvasSize / 2 }; var sectorStart = { x: 4, y: 1 }; var sectorEnd = { x: 1, y: 4 }; var radiusSquared = canvasSize * canvasSize / 4; // create, draw and test a number of random points for (var i = 0; i < count; ++i) { // generate a random point var point = { x: Math.random() * canvasSize, y: Math.random() * canvasSize }; // test if the point is inside the sector var isInside = isInsideSector(point, center, sectorStart, sectorEnd, radiusSquared); // draw the point var $point = $("<div class='dot'></div>") .css({ left: point.x - 3, top: canvasSize - point.y - 8 }) .html("•") .addClass(isInside ? "in" : "out") .appendTo($canvas); } }); </script> </head> <body> <div id="canvas" class="canvas"></div> </body> </html>
您必须根据向量指定扇区的边界。例如,上面的屏幕截图显示了在(4,1)和(1,4)的向量之间拉伸的扇区。
如果您的部门以其他术语指定,例如角度,你必须首先将其转换为矢量,例如使用 tan() 功能。幸运的是,你只需要这样做一次。
tan()
这里的逻辑适用于内角小于180度的扇区。如果您的扇区可以跨越更大的角度,则必须对其进行修改。
此外,代码假定您知道扇区的哪个边界向量是“开始”,哪个是“结束”。如果你不这样做,你可以运行 areClockwise() 在他们身上找出答案。
areClockwise()
请注意,虽然所有这些都可以通过整数运算来完成,但是半径和顺时针测试都使用更大的范围数字,由于平方x和y并将它们相乘。确保使用足够位的整数来保存结果。
我知道你不需要三角学,但是你可以将每个点(在你的子集中)转换为它的极坐标(原点是你的特定点)和阈值 r,theta 哪里 r < R 和 T1 < theta < T2 对应于该部门。它确实有内存效率!
r,theta
r < R
T1 < theta < T2