当前位置: 首页 > news >正文

JavaScript 两个凸多边形之间的切线(Tangents between two Convex Polygons)

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

给定两个凸多边形,我们的目标是找出连接它们的下切线和上切线。

如下图所示,TRLTLR分别代表上切线和下切线。

例如:

输入:第一个多边形:[[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 的上方),我们沿b逆时针方向移动到下一个点,形成直线2。这条直线现在位于多边形b 的上方,这很好。但是,它穿过多边形a ,因此我们沿a顺时针方向移动到下一个点,形成直线 3。直线3仍然穿过多边形a,因此我们继续移动到直线 4。然而,直线 4穿过多边形b,因此我们继续移动到直线 5。最后,直线 5不穿过任何一个多边形,因此它是给定多边形的正确上切线。

为了找到下切线,我们需要反向穿过多边形,即如果直线穿过多边形 b,则接下来顺时针移动;如果直线穿过多边形 a,则接下来逆时针移动。

上切线算法:

L ←连接多边形 a 的最右点和 b 的最左点的线段。当 L 穿过任意多边形时:当 L 穿过多边形 b 时,L ← L':多边形 b 上的点向上移动。当 L 穿过多边形 a 时,L ← L':多边形 a 上的点向上移动。

下切线算法:

L ←连接多边形 a 的最右点和 b 的最左点的线段。当(L 穿过任意多边形)时 { 当(L 穿过 b)时 L ← L':b 上的点向下移动。当(L 穿过 a)时 L ← L':a 上的点向下移动。 }

请注意,上述代码仅计算了上切线。类似的方法也可用于求下切线。

// Determine the quadrant of a point
function quad(p) {
if (p[0] >= 0 && p[1] >= 0) return 1;
if (p[0] <= 0 && p[1] >= 0) return 2;
if (p[0] <= 0 && p[1] <= 0) return 3;
return 4;
}

// Find orientation of triplet (a, b, c)
function orientation(a, b, c) {
let res = (b[1] - a[1]) * (c[0] - b[0]) - (c[1] - b[1]) * (b[0] - a[0]);
if (res === 0) return 0;
return res > 0 ? 1 : -1;
}

// Compare two points based on mid
function compare(p1, p2, mid) {
let p = [p1[0] - mid[0], p1[1] - mid[1]];
let q = [p2[0] - mid[0], p2[1] - mid[1]];

let quadP = quad(p);
let quadQ = quad(q);

if (quadP !== quadQ)
return quadP - quadQ;
return (p[1] * q[0]) - (q[1] * p[0]);
}

// Sort polygon points counter-clockwise
function sortPoints(polygon) {
let n = polygon.length;
let mid = [0, 0];

for (let i = 0; i < n; i++) {
mid[0] += polygon[i][0];
mid[1] += polygon[i][1];
polygon[i][0] *= n;
polygon[i][1] *= n;
}

polygon.sort((p1, p2) => compare(p1, p2, mid));

for (let i = 0; i < n; i++) {
polygon[i][0] = Math.floor(polygon[i][0] / n);
polygon[i][1] = Math.floor(polygon[i][1] / n);
}

return polygon;
}

// Find upper tangent between two convex polygons
function findUpperTangent(a, b) {
let n1 = a.length;
let n2 = b.length;

let maxa = -Infinity;
for (let i = 0; i < n1; i++)
maxa = Math.max(maxa, a[i][0]);

let minb = Infinity;
for (let i = 0; i < n2; i++)
minb = Math.min(minb, b[i][0]);

a = sortPoints(a);
b = sortPoints(b);

if (minb < maxa) {
let temp = a;
a = b;
b = temp;
n1 = a.length;
n2 = b.length;
}

let ia = 0, ib = 0;
for (let i = 1; i < n1; i++)
if (a[i][0] > a[ia][0])
ia = i;

for (let i = 1; i < n2; i++)
if (b[i][0] < b[ib][0])
ib = i;

let inda = ia, indb = ib;
let done = false;

while (!done) {
done = true;
while (orientation(b[indb], a[inda], a[(inda + 1) % n1]) > 0)
inda = (inda + 1) % n1;

while (orientation(a[inda], b[indb], b[(n2 + indb - 1) % n2]) < 0) {
indb = (n2 + indb - 1) % n2;
done = false;
}
}

return [a[inda], b[indb]];
}

// Driver code
let a = [[2, 2],[3, 1],[3, 3],[5, 2],[4, 0]];

let b = [[0, 1],[1, 0],[0, -2],[-1, 0]];

let tangent = findUpperTangent(a, b);

for (let point of tangent) {
console.log(point[0] + " " + point[1]);
}

输出
上切线(upper tangent) (0,1) (3,3)

时间复杂度:O(n1 log (n1) + n2 log(n2))

辅助空间:O(1)

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

http://www.jsqmd.com/news/1199489/

相关文章:

  • ​给父母买食用油应该怎么选?多力这款油营养安全双满分 - 资讯焦点
  • AI如何革新CUDA编程:从强化学习到性能优化
  • pdf转excel最简单方法有哪些?盘点免费在线和本地工具,哪个更省心 - 资讯报道
  • 2026重庆黄金出手别踩亏!全域正规回收门店盘点,透明计价无隐形扣费 - 衡金阁
  • VS Code插件发布全流程:从vsce打包到Marketplace上架避坑指南
  • AI 会抢走哪些人的工作?真正危险的可能不是某个职业
  • Automated HIV Screening on Dutch Electronic Health Records with Large Language Models
  • CentOS 7.9环境搭建与Linux核心技能实战指南
  • C 语言工业级通用组件手写 04:阻塞队列
  • 鼠源CD3E与CD3G异二聚体蛋白的结构特征与应用价值
  • XUnity.AutoTranslator:如何让Unity游戏实现智能实时翻译的完整指南
  • Dify平台:可视化AI应用开发的核心技术与实践
  • Gemini 3.5 新手极速上手指南
  • Windows消息机制:原理、实现与优化技巧
  • 安卓逆向入门:从APK结构解析到动态Hook实战指南
  • 中欧EMBA真的适合外企高管吗?民企占比、适配人群一次讲透 - 资讯快报
  • pdf转excel软件靠谱吗?从出差高铁贴票说起,这三类方案亲测有效 - 资讯报道
  • 武汉钻石回收避坑指南|看懂4C计价逻辑,拆解钻戒变现全套套路 - 奢侈品回收评测
  • Android 8.1精准安装Frida 12.8.10并配置VSCode代码提示完整指南
  • WSL2环境搭建与开发配置全指南
  • 【Atlas】如何优化 Solr 查询性能以提升 Atlas 搜索速度?
  • 2026佛山顺德区卖黄金别踩本地专属套路!30年连锁易奢福大盘金价,结算无额外收费 - 奢侈品回收实体店
  • 东莞LOGO设计公司视维品牌:用策略型视觉,陪制造业把品牌做“实“
  • 人源凝血因子XI重组蛋白的结构、功能与制备策略
  • AI程序员Devin的现实挑战与人类开发者应对策略
  • Codex Skill开发指南:从核心架构到实战优化
  • 数字孪生+AI视觉:C#上位机落地产线仿真与缺陷预测,拒绝PPT架构
  • C++类与对象(上):从struct到class,一文吃透核心概念
  • 南京江宁区探店合集,易奢福全域网点,2026 就近回收黄金不用远跑 - 肉松卷
  • C++实现哈夫曼编码:从原理到文件压缩实战