判断两个形状是否相交(二)-GJK

article/2025/9/25 0:00:34

  • 判断两个形状是否相交二-GJK
    • 原文地址
    • 一 介绍
    • 二凸多边形性质
    • 三Minkowski和
    • 四单纯形
    • 五支持函数
    • 六创建单纯形
    • 七相交检测
    • 八迭代
        • 然后我们开始循环迭代
        • 第二次迭代
        • 第三次迭代
    • 九检测单纯形
    • 结束语

判断两个形状是否相交(二)-GJK

原文地址

一、 介绍:

GJK和SAT一样,只适用于凸多边形。GJK更为强大的地方在于,它可以通过“支持函数”(稍后讨论)支持所有的形状。因此,和SAT不同,你不用对曲边型使用特殊的代码或者方法进行特殊处理,就可以使用GJK。
GJK是一个迭代式的方法但是收敛的非常快,如果使用最新的渗透(分离)向量,它几乎是在一个很短的时间内得出结果。它是SAT在3D环境下的一个很好的替代,就因为SAT要测试的轴de数量非常多。
GJK的最初始的目的是为了计算两个凸边形的距离.GJK同样可以被用作在渗透很短的情况下的碰撞信息,还可以在其他的计算很大的渗透的方法中使用.

二、凸多边形性质:

就像之前说过的一样,GJK是一个只能被用在凸多边形上的方法。我看上一个关于SAT的博文了解更多关于凸多边形的信息。

三、Minkowski和:

GJK算法依靠一个很重要的理论叫做,闵科夫斯基和。闵科夫斯基和在原理上很容易理解:如果你有俩个形状,闵科夫斯基和就是形状 a 的所有的点加上形状b的所有的点,

A + B = {a + b|a∈A, b∈B}

如果两个形状都是凸多边形那么结果也是凸多边形。你可能会想“这又有什么意义呢?”。其实真正的意义所在是不再于“和”而在于“差”,(译者注,这里有些绕,姑且关注“闵科夫斯基差”即可)。

A – B = {a – b|a∈A, b∈B}
(译者注,表示形状A中的所有点和形状B中的所有点相减,如果A中有 n 个点,B中有n个点,那么最终将会产生 n2 个点。)

在我们继续之前申明一下,尽管我们使用的是一个“差”操作,这同样是闵科夫斯基和的一部分,在以后的部分里我把它叫做“闵科夫斯基差”只是为了方便,它的名字同样还是“闵科夫斯基和”。

如果两个形状重叠或者相交那么这两个形状的闵科夫斯基差产生的点的外围形状会包含原点

如果有下图这样两个相交的图形
图示1:两个相交的凸多边形。
做闵科夫斯基差,可以得到12个点。这12个点的包含多边形会包含原点。如下图示:
图示2:闵科夫斯基差
如上面讨论过一样,做这样一个运算将要进行 n2 次减法。如果两个多边形的顶点数目比较多这样会使巨大的运算量。不过幸运的是在使用GJK的时候可以不对所有的点都进行闵科夫斯基差操作,就可以得出想要的结果。

四、单纯形:

我们并不想真的计算出来闵科夫斯基差。取而代之的是我们只需要知道闵科夫斯基差是不是包含原点。如果它包含远点那么我们就可以得出结论,这两个多边形相交,反之亦然。
我们可以做的就是迭代地在闵科夫斯基差里面计算出来一个多边形去试图包含原点。如果我们建造的多边形(当然要在闵科夫斯基差内部)包含原点那么我们就可以说闵科夫斯基差包含原点,我们给我们要创建的这个多边形起名叫做“单纯形”(英文原文Simplex)。
单纯性就是一个三角形,只不过它的订单都是通过闵科夫斯基差计算出来的。

五、支持函数:

那么下一个问题就是我们如何创建这样一个单纯形。单纯形使用一个叫做支持函数的方法去创建。支持函数在给定两个形状之后应该返回一个在闵科夫斯基差内部的点。我们已经知道了我们可以从形状a中得到一个点然后从形状b中得到一个点,将这两个点相减就可以得到一个在闵科夫斯基差边缘上的点。但是我们不想总是得到同一个点。
如果我们让这个支持函数是以一个向量为基础的那么我们就可以保证在使用不同的向量是就可以得到不同的点。换句话说,如果我们让支持函数返回的是在一个方向上的最近的点,我们就可以选择不同的方向得到不同的点。(译者注,这儿看不懂没关系其实很简单,一会看到后面有很详细的例子看看就会明白了,这里只需明白,这个支持函数是输入一个向量返回一个点就行了)。
选择一个方向上的最近的两个点有着非常重要的意义,因为它能够创建一个包含最大面积的单纯形,这样就能够快速地增加让这个函数退出得到结果的机会了。而且,我们可以还可以利这种方式返回的点都在闵科夫斯基边缘的这样一个事实,因此如果我们不能够添加一个沿着一个特定向量的朝向原点方向的一个点,我们就可以得出结论,这个闵科夫斯基差不包含原点。这增加了算法快速得出结论的机会。下面会介绍更多信息。
支持函数如下

public Point support(Shape shape1, Shape shape2, Vector d) {// d is a vector direction (doesn't have to be normalized)// get points on the edge of the shapes in opposite directionsPoint p1 = shape1.getFarthestPointInDirection(d);Point p2 = shape2.getFarthestPointInDirection(d.negative());// perform the Minkowski DifferencePoint p3 = p1.subtract(p2);// p3 is now a point in Minkowski space on the edge of the Minkowski Differencereturn p3;
}

六、创建单纯形:

让我们通过一个实例开始。我们使用在图示2中的图形,运行三次支持函数。
第一次,我们选择d=(1,0)

p1(9,9);
p2(5,7);
p3=p1-p2=(4,2);

第二次 d=(-1,0)

p1=(4,5);
p2=(12,7);
p3=p1-p2=(-8,-2);

注意 p1 可以是(4,5)或者(4,11)。这两个都会产生一个在闵科夫斯基边缘上的点。
最后一次 d = (0, 1)

p1=(4,11);
p2=(10,2);
p3=p1-p2=(-6,9);

我们可以得到这样一个单纯形。
这三次运行的结果如下图
图示3:单纯形示例
(译者注,一定要认真的看这个例子对照着图示2这样才能够看懂之前说的那些东西)

七、相交检测:

我们之前说过,如果两个多边形相交那么他们的闵科夫斯基差就会包含原点。在图示3中单纯形并没有包含原点,但是两个多边形明明相交。这里的问题在于,我们第一次选择的方向d并没有成功的的生产出一个包含原点的单纯形。
如果我们使用d=(0,-1)作为第三次的d,那么

p1=(4,5);
p2=(5,7);
p3=p1-p2=(-1,-2);

这样就能够产生一个下图所示的包含远点的单纯型,这样我们就可以判断出来两个多边形相交。
图示4:包含原点的示例单纯形
所以正如我们所见,d的选择能够影响结果。我们不能保证我们选择的三个点就能够包含原点,我们同样不能够保证闵科夫斯基差包含原点。我们用选择指向原点的点的方式替换原来的选择点的方式。如果我们改变我们选择第三个闵科夫斯基点的方式产生的简单型就能够包含原点了。

d = ...//这里表示还是和上面的前两步一样
a = support(..., d)
d = ...
b = support(..., d)
AB = b - a
AO = ORIGIN - a
d = (AB x AO) x AB//向量的叉乘,这样计算的点//在直线AB和原点同向的一侧
c = support(..., d)

因为d是依靠与ab形成的线,我们可以选择相反的方向作为第二次的d,这样就能够保证b和a的距离尽可能的远。

d = ...
a = support(..., d)
b = support(..., -d)
AB = b - a
AO = ORIGIN - a
d = (AB x AO) x AB
c = support(..., d)

那么现在我们需要做的就是为第一次闵科夫斯基差选择一个d。这里有很多的选择,一个随机的方向,这两个形状的中心连线创建的方向,等等。任何一种都可以,但是有一些选择更优。

八、迭代:

尽管我们改变了之前的做法来判断是否碰撞,但是我们依然没有通过那三个步骤得到一个包含原点的单纯形。我们必须创建单纯形,这样就能够保证我们得到的单型和原点的距离越来越近。迭代过程中有两点需要注意:

  1. 是否已经得到了一个包含原点的单纯形。
  2. 是否有能够得到一个包含原点的单纯型。

下面是算法示意代码:
(译者注:这个伪代码和下面的例子好好看)

Vector d = // choose a search direction
// get the first Minkowski Difference point
Simplex.add(support(A, B, d));
// negate d for the next point
d.negate();
// start looping
while (true) {// add a new point to the simplex because we haven't terminated yetSimplex.add(support(A, B, d));// make sure that the last point we added actually passed the originif (Simplex.getLast().dot(d) <= 0) {// if the point added last was not past the origin in the direction of d// then the Minkowski Sum cannot possibly contain the origin since// the last point added is on the edge of the Minkowski Differencereturn false;} else {// otherwise we need to determine if the origin is in// the current simplexif (Simplex.contains(ORIGIN)) {// if it does then we know there is a collisionreturn true;} else {// otherwise we cannot be certain so find the edge who is// closest to the origin and use its normal (in the direction// of the origin) as the new d and continue the loopd = getDirection(Simplex);}}
}

下面就让我们用这个方法进行测试:
初始化

d = c2 - c1 = (9, 5) - (5.5, 8.5) = (3.5, -3.5) = (1, -1);
//这里的c 表示图形的图心
p1 = support(A, B, d) = (9, 9) - (5, 7) = (4, 2);
Simplex.add(p1);
d.negate() = (-1, 1);

然后我们开始循环迭代:

需要注意的是:(A x B) x C = B(C.dot(A)) – A(C.dot(B))

last = support(A, B, d) = (4, 11) - (10, 2) = (-6, 9);
proj = (-6, 9).dot(-1, 1) = 6 + 9 = 15
// we past the origin so check if we contain the origin
// we dont because we are line
// get the new direction by (AB x AO) x AB 
AB = (-6, 9) - (4, 2)  = (-10, 7);
AO = (0, 0) - (-6, 9) = (6, -9);
(AB x AO) x AB = AO(149) - AB(-123) = (894, -1341) - (1230, -861) 
               = (-336, -480)
               = (-0.573, -0.819)

下面这张图展示了第一次迭代的结果
图示5:第一次循环

第二次迭代

last = support(A, B, d) = (4, 5) - (12, 7) = (-8, -2)
proj = (-8, -2).dot(-336, -480) = 2688 + 960 = 3648
// we past the origin so check if we contain the origin
// we dont (see Figure 6a)
// the new direction will be the perp of (4, 2) and (-8, -2)
// and the point (-6, 9) can be removed
AB = (-8, -2) - (4, 2)  = (-12, -4);
AO = (0, 0) - (-8, -2) = (8, 2);
(AB x AO) x AB = AO(160) - AB(-104) = (1280, 320) - (1248, 416) 
               = (32, -96)
               = (0.316, -0.948)

在第二次迭代之后并没有得到一个包含原点的简单型,但这并不能说明我们不能最终计算出来。在第二次迭代中我们移除了点(-6,9)因为无论何时我们只需要三个点即可,而且在每次迭代开始的时候我们将插入一个新的点。

第二次循环产生的简单型如下图示
第二次迭代产生的简单型
第二次迭代产生的方向如下图示
第二次迭代产生的方向

第三次迭代

last = support(A, B, d) = (4, 5) - (5, 7) = (-1, -2)
proj = (-1, -2).dot(32, -96) = -32 + 192 = 160
// we past the origin so check if we contain the origin
// we do (Figure 7)!(下图)

第三次迭代将产生期望的简单型,如下图
最终结果

九、检测单纯形:

我们忽略了这个算法的两个操作。一个是,我们如何我们如何知道当前的单纯形包含原点,另一个是,我们如何选择下一个方向。在伪代码中,我为了描述方便将这些操作单列出来,但是在实际操作中,他们应该在一块进行,因为他们需要很多相同的信息。
我们可以通过对单纯形进行一系列的简单的点乘操作来判断原点和单纯形的位置关系。第一个要解决的问题是线段问题。让我们看一下上面的第一次循环。在第九行添加了第二个点之后,现在单纯形是一个线段。我们可以检测泰森多边形区域,来判断单纯形是否有可能包含原点。
泰森多边形示例如下图
泰森多边形
线段被定义为从A到B,其中A是最后添加到单纯性中取得。我们知道了A和B都是在闵科夫斯基边缘上的,因此原点不能在R1(上图中的区域)或者R4.我们可以得出这样的假设因为第11行的检测返回false指示出我们可以包含原点。原点只可能落在R2或者R3中,而且一个线段不可能包含原点,所以下一步需要做的就是计算出一个新的方向。这可以按照先前的介绍的,通过AB的叉乘计算出朝向原点的向量。

// the perp of AB in the direction of O can be found by
AB = B - A;
AO = O - A;
perp = (AB x AO) x AB;

这里的问题在于,如果原点落在了单纯形的边上会发生什么样的情况,第11行的检测就会失败。这样会在如下两中情况下发生:
1. 原点在闵科夫斯基内部(译者注,不懂什么意思 这个!)
2. 在闵科夫斯基边缘。第二中情况表示接触但没有渗透(就是没有相交),所以具体如何处理这种情况需要你自己决定。在其他情况下,你可以使用AB的左法线或者右法线作为新的d。

现在让我们检测第二次循环,第二次循环将我们的单纯形转化为了三角形,下图所示。
此处输入图片的描述
白的区域不必测试因为他们通过了第11行的测试。R2不可能包含原点,因为最后的我们选择的方向是相反的方向。所以需要测试的就是R3,R4和R5。我们可以通过(AC X AB) X AB来计算出AB的法线。然后我们通过计算AB的法线点乘AO来判断原点是否在R4区域里。

AB = (-6, 9) - (-8, -2) = (2, 11)
AC = (4, 2) - (-8, -2) = (12, 4)
// (AC x AB) x AB = AB(AB.dot(AC)) - AC(AB.dot(AB))
ABPerp = AB(68) - AC(125)= (136, 748) - (1500, 500)
       = (-1364, 248)
       = (-11, 2)
// compute AO
AO = (0, 0) - (-8, -2) = (8, 2)
ABPerp.dot(AO) = -11 * 8 + 2 * 2 = -84
// its negative so the origin does not lie in R4

通过更多的测试我们可以判断出来原点在:

AB = (-6, 9) - (-8, -2) = (2, 11)
AC = (4, 2) - (-8, -2) = (12, 4)
// (AB x AC) x AC = AC(AC.dot(AB)) - AB(AC.dot(AC))
ACPerp = AC(68) - AB(160)= (816, 272) - (320, 1760)
       = (496, -1488)
       = (1, -3)
// compute AO
AO = (0, 0) - (-8, -2) = (8, 2)
ACPerp.dot(AO) = 1 * 8 + -3 * 2 = 2
// its positive so that means the origin lies in R3

所以我们判断出来原点在R3中,现在我们需要选择一个新的d作为我们得到下一个闵科夫斯基差的点的方向。这很简单,因为我们知道了AC的泰森多边形区域包含原点:

(AC x AO) x AC

现在最终的把所有的情况都考虑在内的算法为:

Vector d = // choose a search direction
// get the first Minkowski Difference point
Simplex.add(support(A, B, d));
// negate d for the next point
d.negate();
// start looping
while (true) {// add a new point to the simplex because we haven't terminated yetSimplex.add(support(A, B, d));// make sure that the last point we added actually passed the originif (Simplex.getLast().dot(d) <= 0) {// if the point added last was not past the origin in the direction of d// then the Minkowski Sum cannot possibly contain the origin since// the last point added is on the edge of the Minkowski Differencereturn false;} else {// otherwise we need to determine if the origin is in// the current simplexif (containsOrigin(Simplex, d) {// if it does then we know there is a collisionreturn true;}}
}public boolean containsOrigin(Simplex s, Vector d) {// get the last point added to the simplexa = Simplex.getLast();// compute AO (same thing as -A)ao = a.negate();if (Simplex.points.size() == 3) {// then its the triangle case// get b and cb = Simplex.getB();c = Simplex.getC();// compute the edgesab = b - a;ac = c - a;// compute the normalsabPerp = tripleProduct(ac, ab, ab);acPerp = tripleProduct(ab, ac, ac);// is the origin in R4if (abPerp.dot(ao) > 0) {// remove point cSimplex.remove(c);// set the new direction to abPerpd.set(abPerp);} else {// is the origin in R3if (acPerp.dot(ao) > 0) {// remove point bSimplex.remove(b);// set the new direction to acPerpd.set(acPerp);} else{// otherwise we know its in R5 so we can return truereturn true;}}} else {// then its the line segment caseb = Simplex.getB();// compute ABab = b - a;// get the perp to AB in the direction of the originabPerp = tripleProduct(ab, ao, ab);// set the direction to abPerpd.set(abPerp);}return false;
}

结束语

到这里 GJK 判断两个凸多边形是否相交就已经翻译完了,原文的下方有很多非常有意义的问答,都是一些这方面的爱好者对作者的提问,作者的耐心回答,很有意义的。如果有时间可以自己看,翻译那个东西太费事了。。。


http://chatgpt.dhexx.cn/article/TSOtcWsK.shtml

相关文章

碰撞检测GJK算法论文解析一

碰撞检测GJK算法论文解析一 碰撞检测Objcet Representation And Distance1.涉及的概念2.内容详解 Preliminaries1.涉及的概念2.内容详解 碰撞检测 碰撞检测是3维游戏内必不可少的一个功能&#xff0c;有了碰撞检测&#xff0c;游戏才能显得更加真实。之前查找碰撞检测的资料&a…

GJK之判断是否相交

由于排版问题,新文章已经更新到 本文新地址 原文地址: http://www.codezealot.org/archives/88 一、 介绍&#xff1a; GJK和SAT一样&#xff0c;只适用于凸多边形。GJK更为强大的地方在于&#xff0c;它可以通过“支持函数”(稍后讨论)支持所有的形状。因此&#xff0c;和SA…

引擎开发_ 碰撞检测_GJK 算法详细介绍

概述 和SAT(分离轴定理)算法一样&#xff0c;GJK算法也只对凸体有效。 GJK算法的优势是&#xff1a;通过support函数&#xff08;后面会详细讲述&#xff09;&#xff0c;从而支持任何凸体形状之间的碰撞检测&#xff1b;相比SAT算法&#xff0c;你不需要一些额外的操作&#x…

Planning-碰撞检测之GJK

原文:dyn4j:GJK (Gilbert–Johnson–Keerthi) 目录 1. Minkowski Sum(明可夫斯基和)2. Simplex3. support函数4. 构建Simplex G J K GJK GJK和 S A T SAT SAT一样用于检测凸多边形&#xff0c;和 S A T SAT SAT不同&#xff0c; G J K GJK GJK可以处理任意形状的凸多边形&#…

GJK算法

转自&#xff1a;http://blog.sina.com.cn/s/blog_833d50630100xw1r.html GJK算法最初用来求三维空间中凸多面体的距离&#xff08;即最近距离&#xff09;&#xff0c;也因此经常用来做碰撞检测&#xff08;距离是否为0&#xff09;。后被推广到n维空间中求凸包之间的距离&…

碰撞检测GJK算法论文解析二

碰撞检测GJK算法论文解析二 The Theoretical Algorithm内容详解 初探The Distance Subalgorithm内容详解 Appendix Ⅱ涉及的概念内容详解 接上文&#xff0c;本篇文章讲解GJK算法论文的第四、第五部分前半部分&#xff0c;这是整个算法最为核心的部分。第四部分阐述了算法的核心…

碰撞检测GJK算法论文解析三

碰撞检测GJK算法论文解析三 再探Appendix Ⅱ内容详解 再探The Distance Subalgorithm内容详解过程1过程2过程3 这里要先纠正上篇文章的一些错误&#xff0c;就是上篇文章的最后其实并没有证明定理3&#xff0c;而只是给出了仿射集系数向量 λ \lambda λ的解的形式&#xff0c;…

GJK碰撞检测(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

物理引擎学习04-GJK计算多边形之间的最近距离

计算多边形之间的最近距离&#xff0c;才是GJK算法原本的目的。只有两个多边形不相交&#xff0c;计算最近距离才有效。如果相交&#xff0c;则最近距离无效&#xff0c;但是可以使用EPA算法要计算碰撞深度。本文的写作目的&#xff0c;主要是对GJK算法的理解和应用。对算法本身…

python碰撞检测算法_GJK碰撞检测算法

现实世界里我们对于是否碰撞的判断可以说极其容易而且准确,比如下图。在二进制的世界里,一切就没这么直观了。 GJK(Gilbert-Johnson-Keerthi Distance Algorithm) GJK 就是此次要实现的碰撞检测算法。如果对碰撞算法有过了解的话,大概率听过另一个碰撞检测算法 SAT(Separati…

【计算几何】凸多面体重叠判断算法:GJK 算法详解 C++代码实现二维情形的凸多边形重叠判断

文章目录 一、GJK 算法简介二、前置知识2.1 二维向量的点乘和叉乘2.2 三维向量叉乘2.3 凸多边形2.4 闵可夫斯基差2.5 单纯形2.6 Support 函数 三、GJK 算法讲解3.1 熟悉 GJK 算法流程3.1.1 多边形重叠的情形3.1.2 多边形不重叠的情形 3.2 总结 GJK 算法步骤3.3 讲解 GJK 算法细…

GJK 算法

GJK 算法(Gilbert–Johnson–Keerthi) 翻译自&#xff1a;http://www.dyn4j.org/2010/04/gjk-gilbert-johnson-keerthi/ 今天&#xff0c;我将讨论dyn4j项目随附的其他碰撞检测算法。您可以找到很多GJK文档&#xff0c;但是其中很多实际上是技术性的&#xff0c;主要是因为它…

碰撞检测算法之GJK算法

简介 参考&#xff1a; 碰撞检测算法之GJK算法 - 知乎 (zhihu.com) 运筹优化】凸多面体重叠判断算法&#xff1a;GJK 算法详解 & C代码实现二维情形的凸多边形重叠判断_c 凸多边形_WSKH0929的博客-CSDN博客 物理引擎学习03-GJK碰撞检测算法基础gjk算法游蓝海的博客-CSDN博客…

物理引擎学习05-GJK和EPA计算穿透向量

EPA&#xff0c;是扩展多边形算法(Epanding Polytop Algorithm) &#xff0c;用来计算两个多边形碰撞的穿透深度和方向&#xff0c;可用于将两个发生碰撞的多边形分离。本文的写作目的&#xff0c;主要是对GJK和EPA算法的理解和应用。对算法本身感兴趣的朋友&#xff0c;可以阅…

物理引擎学习03-GJK碰撞检测算法基础

GJK是由Gilbert&#xff0c;Johnson&#xff0c;Keerthi 三位前辈发明的&#xff0c;用来计算两个凸多面体之间的碰撞检测&#xff0c;以及最近距离。GJK算法可以在O(MN)的时间复杂度内&#xff0c;检测出碰撞&#xff0c;算法在每次迭代的过程中&#xff0c;都会优先选择靠近原…

碰撞检测——GJK算法

目录 碰撞检测——GJK算法 1.GJK算法的原理及思想 1.1 Minkowski Sum&#xff08;明可夫斯基和&#xff09; 1.2 Simplex 1.3 support函数 1.4 构建Simplex 2. GJK算法步骤 3. GJK算法的优缺点分析 4. GJK算法与其他相关算法的比较分析 4.1 GJK算法和SAT算法的比较 …

QPM 之悬浮窗设置信息

QPM 开源地址&#xff1a;https://github.com/ZhuoKeTeam/QPM 更多实用信息&#xff1a; 手机的基本信息AndroidManifest.xml 信息App 中所有的 SharePreference 信息可配置的开关网络接口 手机基础信息 再也不用 去手机的复杂界面查看各种数据&#xff1b;再也不用 下载 辅…

QPM访谈问题

QPM&#xff1a;Quantitative Project Management&#xff0c;量化项目管理 一、访谈问题 1、请简要介绍贵司的QPM管理的管理方式&#xff1f; 依据公司整体商业目标和CMMI要求&#xff0c;制定和部署了《量化项目管理过程》和相关的指南、模板。 在项目执行中&#xff0c;…

QPM 性能监控组件——总篇

QPM &#xff08;Quality Performance Monitor&#xff09; 是一个质量性能监控组件&#xff0c;可以很方便的查看当前 App 的性能和常用数据。目前主要运行在 Android 平台上&#xff0c;通过集成 QPM 组件&#xff0c;可以在 App 中通过悬浮窗可视化相关实时数据。意在帮助广…

IDEA快捷键显示参数提示

一、IDEA显示参数的提示 1、理想状态是这样 2、某度了半天 都是让画show parameter 那个勾的&#xff0c;不是我想要的 IDEA默认的快捷键提示是 " ctrl p"&#xff0c;但是我改成eclipse的快捷键后就没有提示了 File---->settings---->keymap 需要给ecli…