确定一组点在正方形的内部还是外部
Determining if a set of points are inside or outside a square
我有两个:
bool isPointOnShape(int a, int b)
{
}
bool isPointInShape(int a, int b)
{
}
说我有一个正方形,第一点(左下角)是x,y(0,0)第二点(左上)为(0,2),第三个是(2,2),第四为(0),2)。
形状的点为(0,1)(1,2)(2,1)(1,0),形状点为(1,1)
我如何找出形状/形状上的点并返回真实值,以便我可以将其存储在某个地方?
我将为任何可以在直段中分开的形状提供一般解决方案。
因此,正如您可能已经猜到的那样,我将首先将您的"形状"视为完成循环的细分列表。或者简单地放置一个代表循环的点的圆形列表,例如,您的正方形将是此点列表:
0, 0
0, 2
2, 2
2, 0
请注意,我们认为从每个点到下一个都有段,最后一点连接到第一个。同样,我们要求连续点相等,也不是第一个和最后一个。如果有的话,必须在继续之前将其删除。
现在,对于每个段,我们可以确定边界框。例如,给定此段:
a = (0, 2)
b = (2, 2)
那么x中的值范围为[0,2],y中的值是[2,2],这是您的边界框。
您需要的接下来是该细分线行的主管向量。为此,首先计算段的长度:
length = sqrt((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y))
,然后:
director.x = (a.x - b.x)/length
director.y = (a.y - b.y)/length
注意1:当长度为0时,您会有一个无效的段。这就是为什么我们不想要重复点。
注2:使用导演向量而不是使用该行的方程将使事情变得更容易。
现在,给定一个点P,您可以确定该点是否在段中(如果是列表中的点之一)。在其余的情况下,我们首先要查看它是否在轴线对齐边界框内。这是通过检查范围来完成的:
if
(
(p.x >= box.left && p.x <= box.right) &&
(p.y >= box.top && p.y <= box.bottom) // with origin at the top-left corner
)
{
//It is inside of the bounding box
}
,如果是,那么我们计算从点到线的距离0然后在线。现在,由于浮点算术,您可以测试距离是否较小或等于Epsilon,其中Epsilon是很小的数字。
我们使用此公式:
distance vector = (a - p) - ((a - p) · director) * director
distance = the norm of distance vector
其中"·"表示点产品,"*"表示标量产品。
所有所休息是要在段上迭代,因为每个段都计算距离,如果对于任何人,距离小于epsilon,则点"在形状上"。
好的,但是"形状"呢?
好吧,借助拓扑的技巧,我们可以确定一个点是否内部。这是相同的算法窗口将用来填充多边形或多线线(例如,在Microsoft Paint中自由手用自由手来确定所选区域内的内容)。
它是这样的:
计算您必须跨越以从外部到达点的段数。如果数字对,则在外面,如果它很奇怪,则在内部。
您可以从哪个方向上选择达到点。我选择左。
再次,您将在各个细分市场上迭代。对于每个人,我们都需要确定它是否在垂直范围内。为此,使用边界框:
if ((p.y >= box.top && p.y <= box.bottom))
{
//In the vertical range
}
现在,确定该段是左处还是向右:
if (p.x < box.left)
{
//The segment is at the left
}
else if (p.x > box.right)
{
//The segment is at the right
}
else
{
//The segment is close, need further calculation
}
在段接近的情况下,我们需要计算到该段的向量距离并检查其方向。
矢量距离?好吧,我们已经拥有了它,我们正在采取规范来确定距离。现在,而不是采用标准,而是验证X坐标的符号。如果它小于0,则是正确的,如果它超过0,则将其剩下。如果是0 ...这意味着该段是水平的(因为距离向量始终垂直于片段),则可以跳过该段*。
*:实际上,如果该段为水平并且在垂直范围内,则意味着它在段处。段是否为"形状"?
现在,您需要计算左侧的段数,如果奇怪的话,该点在形状内。否则。这也可以使用上升或正确或以下的段来完成。我刚选。
对于在所有细分市场上进行迭代的较大形状都是昂贵的,您可以将这些段存储在某些空间分区数据结构中。这超出了这篇文章的范围。
如果我想您有Rectangle
类,并且此类具有成员bottomLeft
和topRight
,则可以写下类似的内容:
bool Rectangle::isPointOnShape(int x, int y) {
if (x == bottomLeft.x || x == topRight.x)
if (y > bottomLeft.y && y < topRight.y)
return true;
if (y == bottomLeft.y || y == topRight.y)
if (x > bottomLeft.x && x < topRight.x)
return true;
}
bool Rectangle::isPointInShape(int x, int y) {
bool inX = false;
bool inY = false;
if (x > bottomLeft.x && x < topRight.x)
inX = true;
if (y > bottomLeft.y && y < topRight.y)
inY = true;
return (inX && inY);
}
如果您的形状不是矩形,则此功能当然会有所不同。
- 将函数类成员映射到类本身内部
- 试试完美的正方形,你能给点小费吗
- Boost Spirit,获取迭代器内部语义动作
- 我不明白为什么我声明一个空的内部结构并将其传递给构造函数
- 内联函数中具有内部链接的全局变量
- 在函数内部的声明中初始化数组,并在外部使用它
- 如何在不知道向量大小的情况下输入向量内部的向量?
- 卷曲bracers内部结构的声明
- 从函数角度看ID到文件路径的内部与外部映射
- spdlog标头仅与外部fmt一起使用.spdlog错误:'内部':不是'fmt'
- 如何在pugixml中获取节点的内部XML
- 使用C链接在函数内部创建C++模板
- 指针没有更新它在void函数内部指向的值
- 方法内部但循环仍得到预期的不合格id错误C++
- C++:具有内部链接的正向声明常量
- SDL_PollEvent() 无法捕获类函数内部SDL_QUIT?
- libcurl 和 DNS ttl 中的内部连接管理
- 如何修改 lambda 内部字符串的向量
- 如果我将嵌套映射作为多重映射的值,如何将值插入内部映射?
- 确定一组点在正方形的内部还是外部