给定两个凸多边形,我们的目标是确定连接它们的下切线和上切线。
如下图所示,T RL 和T LR分别代表上切线和下切线。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。
例子:
输入: 第一个多边形:\[2, 2, 3, 3, 5, 2, 4, 0, 3, 1]
第二个多边形:\[-1, 0, 0, 1, 1, 0, 0, -2].
输出: 上切线 - 连接 (0,1) 和 (3,3) 的线下切线 - 连接 (0,-2) 和 (4,0) 的线
****解释:****该图像清晰地显示了连接两个多边形的结构和切线

方法:
为了找到上切线,我们首先选择两个点:多边形a的最右边的点和多边形 b 的最左边的点。连接这两点的线标记为线 1 。由于这条线穿过多边形b (即,它没有完全位于其上方),我们沿逆时针方向移动到b 上的下一个点,形成线 2 。这条线现在位于多边形b 上方,这很好。但是,它与多边形a 相交,因此我们沿顺时针方向移动到a 上的下一个点,创建线 3 。线 3 仍然与多边形a 相交,促使再次移动到线 4 。然而,线 4与多边形 b 相交,因此我们继续到线 5 。最后,线 5不与任何一个多边形相交,使其成为给定多边形的正确上切线。

为了找到下切线,我们需要反向移动多边形,即,如果直线穿过多边形 b,则我们接下来顺时针移动,如果直线穿过多边形 a,则我们接下来逆时针移动。
上切线算法:
L ← 连接 a 最右边点和 b 最左边点的线。while (L 穿过任意多边形) { while(L 穿过 b) L ← L' : b 上的点向上移动。while(L 穿过 a) L ← L' : a 上的点向上移动。}
下切线算法:
L ← 连接 a 最右边点和 b 最左边点的线。 while (L 穿过任意多边形) { while (L 穿过 b) L ← L' : b 上的点向下移动。 while (L 穿过 a) L ← L' : a 上的点向下移动。 }
注意,上面的代码只计算了上切线。类似的方法也可以用来计算下切线。
示例代码:
#include <bits/stdc++.h>
using namespace std;
// Determines the quadrant of a point relative to origin
int quad(vector<int> p) {
if (p0 >= 0 && p1 >= 0)
return 1;
if (p0 <= 0 && p1 >= 0)
return 2;
if (p0 <= 0 && p1 <= 0)
return 3;
return 4;
}
// Returns the orientation of ordered triplet (a, b, c)
// 0 -> Collinear, 1 -> Clockwise, -1 -> Counterclockwise
int orientation(vector<int> a, vector<int> b, vector<int> c) {
int res = (b1 - a1) * (c0 - b0) -
(c1 - b1) * (b0 - a0);
if (res == 0)
return 0;
if (res > 0)
return 1;
return -1;
}
// Compare function to sort points counter-clockwise around center
bool compare(vector<int> p1, vector<int> q1, vector<int> mid) {
vector<int> p = {p10 - mid0, p11 - mid1};
vector<int> q = {q10 - mid0, q11 - mid1};
int one = quad(p);
int two = quad(q);
if (one != two)
return (one < two);
return (p1 * q0 < q1 * p0);
}
// Sorts the polygon points counter-clockwise
vector<vector<int>> sortPoints(vector<vector<int>> polygon) {
vector<int> mid = {0, 0};
int n = polygon.size();
// Calculate center (centroid) of the polygon
for (int i = 0; i < n; i++) {
mid0 += polygoni0;
mid1 += polygoni1;
polygoni0 *= n;
polygoni1 *= n;
}
// Sort points based on their angle from the center
sort(polygon.begin(), polygon.end(),
mid(vector<int> p1, vector<int> p2) {
return compare(p1, p2, mid);
});
// Divide back to original coordinates
for (int i = 0; i < n; i++) {
polygoni0 /= n;
polygoni1 /= n;
}
return polygon;
}
// Finds the upper tangent between two convex polygons a and b
// Returns two points forming the upper tangent
vector<vector<int>> findUpperTangent(vector<vector<int>> a,
vector<vector<int>> b) {
int n1 = a.size(), n2 = b.size();
// Find the rightmost point of polygon a and leftmost point of polygon b
int maxa = INT_MIN;
for (auto& p : a)
maxa = max(maxa, p0);
int minb = INT_MAX;
for (auto& p : b)
minb = min(minb, p0);
// Sort both polygons counter-clockwise
a = sortPoints(a);
b = sortPoints(b);
// Ensure polygon a is to the left of polygon b
if (minb < maxa)
swap(a, b);
n1 = a.size();
n2 = b.size();
// Find the rightmost point in a
int ia = 0, ib = 0;
for (int i = 1; i < n1; i++)
if (ai0 > aia0)
ia = i;
// Find the leftmost point in b
for (int i = 1; i < n2; i++)
if (bi0 < bib0)
ib = i;
// Initialize starting points
int inda = ia, indb = ib;
bool done = false;
// Find upper tangent using orientation checks
while (!done) {
done = true;
// Move to next point in a if necessary
while (orientation(bindb, ainda, a(inda + 1) % n1) > 0)
inda = (inda + 1) % n1;
// Move to previous point in b if necessary
while (orientation(ainda, bindb,
b(n2 + indb - 1) % n2) < 0) {
indb = (n2 + indb - 1) % n2;
done = false;
}
}
// Return the points forming the upper tangent
return {ainda, bindb};
}
// Main driver code
int main() {
vector<vector<int>> a = {{2, 2}, {3, 1}, {3, 3}, {5, 2}, {4, 0}};
vector<vector<int>> b = {{0, 1}, {1, 0}, {0, -2}, {-1, 0}};
vector<vector<int>> tangent = findUpperTangent(a, b);
for(auto it:tangent){
cout<<it0<<" "<<it1<<"\n";
}
return 0;
}
输出
上切线 (0,1) (3,3)
时间复杂度: O(n1 log (n1) + n2 log(n2))
辅助空间: O(1)
如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。