【原创】《矩阵的史诗级玩法》连载三:判断一个点是否在矩形内(支持带旋转的)

        发完上一篇文章之后,我的积极性突然被打击了下。在相关文章列表中,我找到了一个自己之前没听过的词语——影射几何。度娘告诉我,这门学科跟我所谓的“史诗级玩法”似乎有共通之处。也就是说,我拿来装逼的这玩意儿,不过是别人几百年前就玩烂了的一件玩具而已。但无论如何,我在三维家讲课,不少同事仍然表示收获颇丰,所以我选择了坚持。


        判断点与图形的关系,已经是老生常谈的话题了。矩形和圆可谓是最Low的两种图形,究其原因,是其具备了太多基础几何的特性(解析几何以前所学习的教科书内容我都给归到基础几何的范畴),一些方式特殊并且难度很低的技巧即可把大部分实际问题给完美解决掉。


        技术狂人重点关注的,往往是多边形的碰撞检测。它不仅应用广泛(游戏里各种复杂的图形都会用多边形近似表示),而且有深挖的空间(比如含洞,含岛,缠绕型多边形,都蕴含着各种高深的学问)。再者,多边形碰撞的效率优化也够大神们玩足几年了。


        而我写的教程则把重点放到了矩阵的奇葩应用上。为了让大家在理解的过程中有个平缓的过渡,我就先从最简单的圆和矩形开始(上篇讲的就是圆)。讲课的时候,我是这篇文章和上一篇都安排到了同一节课上,但阅读博客的时间跟上课时间不一样。现在这个年代的读者大多都在利用碎片化的时间进行学习,所以我分成了两篇。


        废话太多了,转入正题。


        对于没被旋转的矩形来说,判断它在不在矩形内实在太简单了。如下图,只要判断点的x坐标是否大于-3小于3,并且y坐标是否大于-2小于2。


        那么,如果矩形被旋转了呢?比如30度那样。

        如果你理解了上一篇的套路,那我相信你已经猜到我接下来要怎么做了, 就是矩形和要被判断的点一起旋转-30度,让矩形还原到旋转前的状态。

        旋转完成,就可以用回最初的简单方法,判断坐标的范围。所以剩下来的问题只差如何求出被判断点旋转-30度之后的坐标了。


        旋转角度跟平面坐标的关系几乎都基于三角函数(也有大神喜欢玩向量),现在我们也用类似的方法。


        一个点在绕坐标原点O旋转的过程中,它到O的距离始终不变(理解成圆周运动就好了),此处我用字母R表示这个距离,如下图所示。

        R是可以根据勾股定理算出来的,但我们不急着算,因为这里还涉及角度。


        此处,最重要的角度非OP与x轴的夹角莫属。如下图,假设∠POA=θ,那么显然, ∠P'OA=θ-30°。为什么不是+30呢?这是因为现在所有的点都在y轴的负方向。所以用的是减而不是加。此外,θ在这里也是负数。

        在直角三角形OAP中,根据三角函数的定义,有OA/OP=cosθ,即x/R=cosθ,所以x可以用Rcosθ代替,类似地,P的y坐标就等于Rsinθ,而P'也不难推导出来了,如上图所示。


        从这个式子来看,要解出R和θ才能代入计算。但实际上三角函数部分可以展开。代入两角和差三角函数公式就能得到


        Rcos( θ-30°)=Rcosθcos30°+Rsinθsin30°
        Rsin( θ-30°)=Rsinθcos30°-Rcosθsin30°

        不懂得两角和差三角函数的朋友可以自行百度,以前我讲课的时候还把这个当常识了,却没想到还真的有人没学过或者还给了老师尴尬,所以有一次我还特地讲了一节专门推导两角和差三角函数的课(有录视频的,有需要的我可以发网盘地址到这儿),这里就懒得再展开了。


        展开式有个很神奇的地方,R和 θ可以被完全消掉,因为Rcosθ=x,Rsinθ=y,所以有

        Rcos( θ-30°) =Rcosθcos30°+Rsinθsin30°= xcos30°+ysin30°

        Rsin(θ-30°)=Rsinsθcos30°-Rcosθsin30°=ycos30°-xsin30°


        把x=2.5,y=-1代入,得到新坐标


        X= xcos30 °+ysin30°=1.665

        Y=ycos30°-xsin30°=-2.117


        旋转后的x在-3到3之间,但y不在-2到2之间,所以判断出来了(2.5,-1)这个点不在旋转了30度的矩形内。


        同理,前面展示的(2.5,1.5)这个点,算出的结果是

        X=xcos30°+ysin30°=2.915

        Y=ycos30°-xsin30°=0.049


        x在-3到3之间,y在-2到2之间,因此(2.5,1.5)这个点在旋转了30度的矩形内。


        今天这篇文章,教科书的味道似乎浓了点,但是旋转的套路却又是矩阵变换的一种。因此说穿了,所谓的矩阵史诗级玩法,无非是中学数学的基因重组的结果。


        单独的缩放或者旋转,矩阵似乎没有存在的必要,但如果两种乃至以上的变换组合在一起,仍然用这两篇文章的单独套路来分析的话,就会显得有点绕了。所以下一篇文章,我会让缩放和旋转这两个物种来一次奇妙的合体,从而进化出真正高逼格的——嗯,矩阵,敬请期待!




  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
判断一个三维点是否在一个可随意旋转的长方体内,可以使用以下C++代码表示: ```cpp #include <iostream> #include <vector> #include <Eigen/Dense> using namespace Eigen; // 定义表示长方体的结构体 struct Box { Vector3d position; // 长方体中心点坐标 Vector3d size; // 长方体尺寸(宽度、高度、深度) Matrix3d rotation; // 长方体旋转矩阵 }; // 判断是否在长方体内部的函数 bool pointInBox(const Vector3d& point, const Box& box) { // 将点坐标转换到以长方体中心为原点的局部坐标系 Vector3d localPoint = point - box.position; // 将点坐标应用长方体的逆旋转变换 Vector3d rotatedPoint = box.rotation.inverse() * localPoint; // 判断是否在长方体边界内 bool inXRange = (rotatedPoint.x() >= -box.size.x() / 2.0) && (rotatedPoint.x() <= box.size.x() / 2.0); bool inYRange = (rotatedPoint.y() >= -box.size.y() / 2.0) && (rotatedPoint.y() <= box.size.y() / 2.0); bool inZRange = (rotatedPoint.z() >= -box.size.z() / 2.0) && (rotatedPoint.z() <= box.size.z() / 2.0); return inXRange && inYRange && inZRange; } int main() { // 创建一个长方体 Box box; box.position << 0.0, 0.0, 0.0; // 长方体中心点坐标 box.size << 2.0, 1.0, 3.0; // 长方体尺寸 box.rotation = AngleAxisd(M_PI / 4, Vector3d::UnitZ()).matrix(); // 绕Z轴旋转45度 // 创建一个点 Vector3d point(1.0, 0.5, 1.0); // 判断是否在长方体内部 bool isInBox = pointInBox(point, box); if (isInBox) { std::cout << "Point is inside the box." << std::endl; } else { std::cout << "Point is outside the box." << std::endl; } return 0; } ``` 上述代码使用了Eigen库来进行向量和矩阵计算。通过定义`Box`结构体来表示长方体,其中包含了长方体的位置、尺寸和旋转矩阵。`pointInBox`函数用于判断是否在长方体内部,首先将点坐标转换到以长方体中心为原点的局部坐标系,然后应用长方体的逆旋转变换得到旋转后的点坐标,最后判断是否在长方体边界内。 在`main`函数中创建了一个长方体和一个点,并调用`pointInBox`函数来判断是否在长方体内部,最后输出结果。 请注意,以上代码仅为示例,具体实现可能需要根据您的代码环境和需求进行适当的调整。 希望对您有所帮助!如果您还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值