RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1569441
Accepted
Mikhajlo
Mikhajlo
Asked:2024-02-29 03:57:23 +0000 UTC2024-02-29 03:57:23 +0000 UTC 2024-02-29 03:57:23 +0000 UTC

如何求平面上任意点的物体之间内切圆的最大半径?

  • 772

有一架飞机,上面有许多不同的物体。如果这很重要,那就让有不同半径的圆或正方形——这并不重要。就说圆圈吧。

对于任意点的任务是快速确定哪个邻域未被占用。也就是说,对于圆,我们只需查看从中心到该点的距离减去圆的半径,然后寻找最小值。

但圈子多,时间少。解决这个问题最简单的方法是什么?我研究了四叉树、R 树。但要么我不太理解他们的想法,要么他们适合找点,但不适合找圆。对于点 - 如果四叉树中最近的点位于相邻象限 - 这对我们有什么帮助?不管怎样,事实证明几乎整棵树都需要重新考虑?

告诉我在这种情况下应该使用什么算法?检查尽可能少的不同圆圈?

首先,我们可以假设这些圆不相交(如果有帮助的话)。但一般来说,这不是事实。

алгоритм
  • 1 1 个回答
  • 89 Views

1 个回答

  • Voted
  1. Best Answer
    Stanislav Volodarskiy
    2024-02-29T14:49:21Z2024-02-29T14:49:21Z

    理论

    构建搜索树

    对于沿轴定向的圆和正方形,我们将学习确定从正方形中的点到圆的最短距离:d min。如果它们相交,我们就将该距离视为零。我们还将确定从正方形点到圆的最大距离:d max。如果正方形完全在圆内,我们将其设置为零。

    让我们有一个正方形和一组圆形。对于所有圆,我们选择最大距离中的最小值:h = min{d max }。我们将条件d min ≤ h的圆的索引写为正方形。如果该点落在一个正方形中,您将只需要计算到这组圆的距离,其余的距离正好更远。

    让我们用一个正方形覆盖我们想要寻找最近的圆的区域。让我们计算一下合适的圆圈列表。如果列表太长,请将正方形分成四个较小的正方形,然后递归地重复构建列表。如果圆列表不长于某个阈值,则递归停止。递归的深度也必须受到限制。

    本土化

    点的定位是这样完成的:该点相对于正方形进行定位,然后选择它的四分之一,依此类推,直到我们到达纸张。让我们计算工作表中圆列表中的点到圆的最小距离。

    定位时间包括通过正方形下降(不超过最大递归深度)并计算列表到圆的距离(通常不超过列表长度的阈值)。

    该方法不限于圆圈。如果您知道如何构造从正方形到图形的最小和最大距离,则该图形可以参与定位。

    缺陷

    如果平面上存在最大空圆同时接触k 个障碍物的点,则正方形中的列表将至少为k长。换句话说,如果 Voronoi 图包含高度顶点,定位会浪费大量内存并且速度很慢。如果我们准确地解决这个问题,那么这个弊端是无法避免的。如果可以以一定的精度返回答案,则可以将列表缩小到所需的大小。

    实际上,除非您以特殊方式设计场景,否则十个圆圈聚集在一个公共点周围的可能性微乎其微。此外,你有一切手段在构建搜索树的阶段检测问题,并以另一种方式解决在一个不好的、非常小的方格中的定位问题,当然,如果你想出这样的方法的话。

    例子

    const sub = ([x1, y1], [x2, y2]) => [x1 - x2, y1 - y2];
    const dot = ([x1, y1], [x2, y2]) => x1 * x2 + y1 * y2;
    const mul = ([x, y], f) => [f * x, f * y];
    const dist = (p1, p2) => Math.hypot(...sub(p1, p2));
    
    const minDistPointSegment = (q, [p1, p2]) => {
        const dp = sub(p2, p1);
        const dq = sub(q, p1);
    
        const a = Math.max(0, Math.min(1, dot(dq, dp) / dot(dp, dp)));
        return dist(dq, mul(dp, a));
    };
    
    const minDist = ([[x1, y1], [x2, y2]], [x, y, r]) => {
        if (x1 <= x && x <= x2 && y1 <= y && y <= y2) {
            return 0;
        }
    
        return Math.max(0, Math.min(
            minDistPointSegment([x, y], [[x1, y1], [x2, y1]]),
            minDistPointSegment([x, y], [[x2, y1], [x2, y2]]),
            minDistPointSegment([x, y], [[x2, y2], [x1, y2]]),
            minDistPointSegment([x, y], [[x1, y2], [x1, y1]])
        ) - r);
    };
    
    const maxDist = ([[x1, y1], [x2, y2]], [x, y, r]) => Math.max(0, Math.max(
        dist([x, y], [x1, y1]),
        dist([x, y], [x2, y1]),
        dist([x, y], [x2, y2]),
        dist([x, y], [x1, y2])
    ) - r);
    
    const aMin = a => a.reduce((a, b) => Math.min(a, b), Infinity);
    
    const selectDisks = (rect, disks) => {
        const h = aMin(disks.map(d => maxDist(rect, d)));
        if (h == 0) {
            for (const d of disks) {
                if (maxDist(rect, d) == 0) {
                    return [d];
                }
            }
        }
        return disks.filter(d => minDist(rect, d) <= h);
    };
    
    const buildSearchTree = (depth, length, rect, disks) => {
        const selected = selectDisks(rect, disks);
        if (selected.length <= length || depth <= 0) {
            const maxRadius = (x, y) => [
                Math.max(0, aMin(selected.map(
                    ([cx, cy, r]) => Math.hypot(x - cx, y - cy) - r
                ))),
                depth,
                selected.length
            ];
            return [maxRadius, rect, []];
        }
        const [[x1, y1], [x2, y2]] = rect;
        const xm = (x1 + x2) / 2;
        const ym = (y1 + y2) / 2;
    
        const subtrees = [
            buildSearchTree(depth - 1, length, [[x1, y1], [xm, ym]], selected),
            buildSearchTree(depth - 1, length, [[xm, y1], [x2, ym]], selected),
            buildSearchTree(depth - 1, length, [[x1, ym], [xm, y2]], selected),
            buildSearchTree(depth - 1, length, [[xm, ym], [x2, y2]], selected)
        ];
    
        const maxRadius = (x, y) => subtrees[
            (x < xm) ? ((y < ym)? 0 : 2) : ((y < ym)? 1 : 3)
        ][0](x, y);
    
        return [maxRadius, rect, subtrees];
    };
    
    const makeRect = (svg, [[x1, y1], [x2, y2]]) => {
        const rect = document.createElementNS(
            'http://www.w3.org/2000/svg',
            'rect'
        );
        rect.setAttribute('x', x1);
        rect.setAttribute('y', y1);
        rect.setAttribute('width', x2 - x1);
        rect.setAttribute('height', y2 - y1);
        rect.setAttribute('stroke', 'grey');
        rect.setAttribute('fill', 'none');
        svg.appendChild(rect);
    };
    
    const makeCircle = (svg, [x, y, r]) => {
        const circle = document.createElementNS(
            'http://www.w3.org/2000/svg',
            'circle'
        );
        circle.setAttribute('cx', x);
        circle.setAttribute('cy', y);
        circle.setAttribute('r', r);
        circle.setAttribute('stroke', 'red');
        circle.setAttribute('fill', 'none');
        svg.appendChild(circle);
    };
    
    const makeDisk = svg => {
    
        const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
        svg.appendChild(group);
    
        const moveGroup = (x, y) => {
            const ctm = group.getCTM();
            ctm.e = x;
            ctm.f = y;
    
            const t = svg.createSVGTransform();
            t.setMatrix(ctm);
    
            group.transform.baseVal.initialize(t);
        };
    
        const center = document.createElementNS(
            'http://www.w3.org/2000/svg',
            'circle'
        );
        center.setAttribute('r', 2);
        center.setAttribute('stroke', 'black');
        center.setAttribute('fill', 'black');
        group.appendChild(center);
    
        const circle = document.createElementNS(
            'http://www.w3.org/2000/svg',
            'circle'
        );
        circle.setAttribute('stroke', 'black');
        circle.setAttribute('fill', 'none');
        group.appendChild(circle);
    
        const text = document.createElementNS(
            'http://www.w3.org/2000/svg',
            'text'
        );
        group.appendChild(text);
    
        return {
            'move': moveGroup,
            'setRadius': r => circle.setAttribute('r', r),
            'setText': t => text.textContent = t
        };
    };
    
    const x3 = x => (-2 * x + 3) * x * x;
    const random2 = () => x3(x3(Math.random()));
    
    const main = () => {
        const body = document.getElementsByTagName('body')[0];
    
        const svg = document.createElementNS(
            'http://www.w3.org/2000/svg',
            'svg'
        );
        const width = 600;
        const height = 200;
        svg.setAttribute('width', width);
        svg.setAttribute('height', height);
        body.appendChild(svg);
    
        // const n = 100000;
        const n = 100;
        const maxR = 40;
        const disks = [];
        for (let i = 0; i < n; ++i) {
            disks.push([
                width * random2(),
                height * random2(),
                maxR * Math.random()
            ]);
        }
    
        const maxDepth = 10;
        const size = Math.max(width, height);
        const tree = buildSearchTree(
            maxDepth,
            5,
            [[0, 0], [size, size]],
            disks
        );
    
        const drawTree = tree => {
            makeRect(svg, tree[1]);
            tree[2].forEach(drawTree);
        };
        drawTree(tree);
    
        disks.forEach(d => makeCircle(svg, d));
    
        const disk = makeDisk(svg);
    
        svg.onmousemove = e => {
            const p = svg.createSVGPoint();
            p.x = e.clientX;
            p.y = e.clientY;
            const {x, y} = p.matrixTransform(svg.getScreenCTM().inverse());
            disk.move(x, y);
    
            const [r, depth, length] = tree[0](x, y);
            disk.setRadius(r);
            disk.setText(`${maxDepth - depth}+${length}`);
        };
    };
    
    document.addEventListener('DOMContentLoaded', main);

    红色圆圈是障碍物。黑色圆圈跟随鼠标光标并显示给定点的最大半径。黑圈里面有两个数字:树中某个节点的深度和该节点中障碍盘的数量。运行代码并将鼠标光标移到图片上。在一百个随机障碍物的示例中,对于任何光标位置,计算到最多五个障碍物的距离。

    图片

    为了绘制加权 Voronoi 图,列表长度的阈值设置为 1。然后,仅当正方形位于一个圆的 Voronoi 单元内部时,递归才会停止。在图的边缘附近,除法继续直至递归深度的极限。小灰色方块沿着图的边缘和顶点聚集,并且变得可见。

    不同半径的圆之间的细胞边界是弯曲的——这些是双曲线的片段。

    使用类似的代码,您可以绘制加权 Voronoi 图。

    • 3

相关问题

  • Golang 中的堆栈实现

  • 二部图中的最大匹配

  • 求两个数的差模为 m 的倍数的算法

  • 如何将平面几何对象表示为矢量以应用于人工神经网络的输入?[关闭]

  • 如何正确执行矩形的 Delaunay 三角剖分?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5