判断任意一点是否在矩形内(矩形可能与坐标轴有一定夹角)

1. 理论方法

1.1 点乘实现理论

  • 问题

如何判断点 P P P是否在被 P 1 P 2 P 3 P 4 P_1P_2P_3P_4 P1P2P3P4四个点围成的矩形框内?

  • 方法

如果在矩形内:点 P P P与矩形4个角的连线与任意轴形成的夹角都为锐角。可以用向量的点乘判断角度是否为锐角。具体方法如下图所示。

在这里插入图片描述
所以可以通过下列公式判断:

点 P 位 于 矩 形 框 内 ⇔ { ∠ P P 1 P 4 < 90 ∠ P P 1 P 2 < 90 ∠ P P 3 P 4 < 90 ∠ P P 3 P 2 < 90 ⇔ { P 1 P ⇀ ∗ P 1 P 4 ⇀    > 0 P 1 P ⇀ ∗ P 1 P 2 ⇀    > 0 P 3 P ⇀ ∗ P 3 P 4 ⇀    > 0 P 3 P ⇀ ∗ P 3 P 2 ⇀    > 0 点P位于矩形框内\Leftrightarrow{\left\{\begin{array}{l}\angle PP_1P_4<90\\\angle PP_1P_2<90\\\angle PP_3P_4<90\\\angle PP_3P_2<90\end{array}\right.}\Leftrightarrow{\left\{\begin{array}{l}\overset\rightharpoonup{P_1P}\ast\overset\rightharpoonup{P_1P_4}\;>0\\\overset\rightharpoonup{P_1P}\ast\overset\rightharpoonup{P_1P_2}\;>0\\\overset\rightharpoonup{P_3P}\ast\overset\rightharpoonup{P_3P_4}\;>0\\\overset\rightharpoonup{P_3P}\ast\overset\rightharpoonup{P_3P_2}\;>0\end{array}\right.} PPP1P4<90PP1P2<90PP3P4<90PP3P2<90P1PP1P4>0P1PP1P2>0P3PP3P4>0P3PP3P2>0

1.2 叉乘实现理论

只需要判断点 P P P是否在上下两条边和左右两条边之间就可以,判断一个点是否在两条线段之间夹着,可以使用叉乘来判断,当 ( P 1 P 2 × P 1 P ) ∗ ( P 3 P 4 × P 3 P ) > = 0 (P_1P_2\times P_1P)\ast(P_3P_4\times P_3P)>=0 (P1P2×P1P)(P3P4×P3P)>=0时,说明点 P P P P 1 P 2 P_1P_2 P1P2 P 3 P 4 P_3P_4 P3P4的中间。同理判断两边即可。所以点 P P P在矩形内的条件为:
( P 1 P 2 × P 1 P ) ∗ ( P 3 P 4 × P 3 P ) > = 0      a n d      ( P 2 P 3 × P 2 P ) ∗ ( P 4 P 1 × P 4 P ) > = 0 (P_1P_2\times P_1P)\ast(P_3P_4\times P_3P)>=0\;\;and\;\;(P_2P_3\times P_2P)\ast(P_4P_1\times P_4P)>=0 (P1P2×P1P)(P3P4×P3P)>=0and(P2P3×P2P)(P4P1×P4P)>=0

2. 代码实现

2.1 点乘方法实现

#include<iostream>
struct MPoint
{
    double x;
    double y;
};
struct RectPoint
{
    MPoint p1;
    MPoint p2;
    MPoint p3;
    MPoint p4;
};
bool isPointInRect(MPoint p, RectPoint rect)
{
    if ((rect.p1.x - p.x) * (rect.p1.x - rect.p4.x) + (rect.p1.y - p.y) * (rect.p1.y - rect.p4.y) < 0)
        return false;
    if (((rect.p1.x - p.x) * (rect.p1.x - rect.p2.x) + (rect.p1.y - p.y) * (rect.p1.y - rect.p2.y)) < 0)
        return false;
    if (((rect.p3.x - p.x) * (rect.p3.x - rect.p4.x) + (rect.p3.y - p.y) * (rect.p3.y - rect.p4.y)) < 0)
        return false;
    if (((rect.p3.x - p.x) * (rect.p3.x - rect.p2.x) + (rect.p3.y - p.y) * (rect.p3.y - rect.p2.y)) < 0)
        return false;
    return true;
}
int main(int argc,char *argv[])
{
    RectPoint rect;
    MPoint p;
    //添加矩形框点
    rect.p1.x = 1;
    rect.p1.y = 0;
    
    rect.p2.x = -1;
    rect.p2.y = 0;
    
    rect.p3.x = 0;
    rect.p3.y = 1;
    
    rect.p4.x = 0;
    rect.p4.y = -1;

    p.x = 0.5;
    p.y = 0.5;
    std::cout<<"("<<p.x<<", "<<p.y<<")"<<"是否在矩形框内:"<<std::boolalpha<<isPointInRect(p, rect)<<std::endl;//1 or 0 use noboolalpha
    p.x = 0.5;
    p.y = 3.0;
    std::cout<<"("<<p.x<<", "<<p.y<<")"<<"是否在矩形框内:"<<std::boolalpha<<isPointInRect(p, rect)<<std::endl;//1 or 0 use noboolalpha
    
    return 1;
}

输出:

(0.5, 0.5)是否在矩形框内:true
(0.5, 3)是否在矩形框内:false

2.2 叉乘方法实现

#include <iostream>

struct Point
{
	float x;
	float y;
	Point(float x, float y)
	{
		this->x = x;
		this->y = y;
	}
};
// 计算 |p1 p2| X |p1 p|
float GetCross(Point &p1, Point &p2, Point &p)
{
	return (p2.x - p1.x) * (p.y - p1.y) - (p.x - p1.x) * (p2.y - p1.y);
}
bool IsPointInMatrix(Point &p)
{
	Point p1(0, 5);
	Point p2(0, 0);
	Point p3(5, 0);
	Point p4(5, 5);

	return GetCross(p1, p2, p) * GetCross(p3, p4, p) >= 0 && GetCross(p2, p3, p) * GetCross(p4, p1, p) >= 0;
}
using namespace std;
int main(int argc, char *argv[])
{
	Point testPoint(3, 4);

	cout << "the point is " << (IsPointInMatrix(testPoint) ? "in the Matrix ." : "not in the matrix .") << endl;

	testPoint.x = 5;
	testPoint.y = 34;
	cout << "the point is " << (IsPointInMatrix(testPoint) ? "in the Matrix ." : "not in the matrix .") << endl;
	return 0;
}

输出:

the point is in the Matrix .
the point is not in the matrix .

参考:https://blog.csdn.net/weixin_43619346/article/details/107513919?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163611842416780271588491%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=163611842416780271588491&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-107513919.first_rank_v2_pc_rank_v29&utm_term=%E5%88%A4%E6%96%AD%E4%B8%80%E4%B8%AA%E7%82%B9%E6%98%AF%E5%90%A6%E5%9C%A8%E7%9F%A9%E5%BD%A2%E5%86%85&spm=1018.2226.3001.4187

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

非晚非晚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值