仅通过整数算术和加减乘基本运算就可以检查一个点是否在扇区内。
对于一个位于circular sector 内的点,它必须满足以下测试:
- 必须从扇区的起始“臂”逆时针定位。
- 它必须从扇区的末端臂顺时针定位。
-
它必须比扇形半径更接近圆心。
顺时针测试
要测试一个向量 v2 是否顺时针指向另一个向量 v1,请执行以下操作:
找到v1的逆时针normal vector。法线向量与原始向量成 90 度角。这是straightforward to do:如果v1=(x1,y1),那么逆时针法线是n1=(-y1,x1)。
-
求v2在法线上的投影大小。这可以通过计算 v2 的dot product 和法线来完成。
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() 函数。幸运的是,您只需执行一次。
这里的逻辑适用于内角小于 180 度的扇区。如果您的扇区可以跨越更大的角度,则必须对其进行修改。
此外,代码假定您知道扇区的哪个边界向量是“开始”,哪个是“结束”。如果你不知道,你可以在他们身上运行areClockwise() 来找出答案。
1234563确保使用足够位的整数来保存结果。