发布时间:2026/9/2 5:54:10
Matlab实现Voronoi图:从原理到代码,解决空间划分与选址问题 简介面向计算几何与科学计算的Matlab Voronoi图生成代码包适合需要从底层理解Voronoi图与Delaunay三角化的学生、研究者或算法爱好者。资源打破内置函数的黑箱围绕点集剖分、外接圆判断、邻接关系构建等核心步骤提供了一套可逐行研读的自定义函数实现。压缩包共11个文件以9个.m源文件和2张.png结果图为主整体约131KB结构紧凑便于对照学习。目前已有5921人学习下载。代码将Voronoi图生成拆分为多个独立模块三角剖分、线段构建、相邻三角形查找、外接圆计算与空圆条件判断等使用者既能按步骤理解几何关系也能直接调用或修改这些函数用于实际项目。两幅结果图直观对比了不同实现路径的输出效果方便验证算法正确性可作为Matlab图形学课程设计或计算几何入门的重要参考。 写到Voronoi图我得先讲个真事。前阵子有个做充电桩选址的朋友找我说他们现在划分每个站点的服务范围还靠人工画圈地图上几十个点一个个手动画边界干到凌晨两点还没弄完。我说你早该用Voronoi图了这玩意儿就是干这个的。他把数据发我我写了一段Matlab不到一分钟服务范围全部自动切好还带面积统计。他当场愣住问我这到底是什么神仙技术。其实真不是神仙技术就是计算几何里一个经典工具Matlab里实现它比你想象中简单但坑也确实不少。这篇我就把Voronoi图的原理、Matlab里几个函数的选型思路、完整可跑的代码、还有我踩过的那些坑一次性讲清楚。1. Voronoi图是啥能帮我解决什么问题1.1 从奶茶店选址说起想象一条街上开了几家奶茶店顾客自然选离自己最近的那家。如果按“最近原则”把整条街划分成几块服务区每家店独占一块这块区域里任何一个位置到这家的距离都小于到其他家的距离——这个划分结果就是Voronoi图。在计算几何里叫Voronoi Diagram气象学里叫泰森多边形通信工程里管它叫Voronoi分区有些做地理分析的也叫它Dirichlet tessellation。名字一大堆本质都是同一个东西。数学定义也不复杂给定平面上的一组种子点也叫站点、生成点平面被分成若干个单元每个单元内部的所有点到对应种子点的欧氏距离都小于到其他任意种子点的距离。写出来就是长这样[ V(p_i) { x \in X \mid d(x, p_i) \le d(x, p_j), \forall j \ne i } ]通俗讲就是每个种子点圈一块地谁距离它最近谁就归它管。1.2 我见过最实用的五大应用场景这玩意儿能干活的地方太多了我简单列几个我自己实际碰过或跟人聊过的场景充电桩、快递站、基站选址给出所有站点的坐标自动划出每站的服务范围一眼看出哪些站点服务面积过大、哪些区域覆盖重叠。城市公共设施规划学校、医院、消防站的服务半径分析按Voronoi单元算覆盖人口密度比拿圆规画圈科学得多。材料科学晶粒结构模拟晶粒长大过程天然就是Voronoi图的演化过程很多论文里的微观结构示意图就是Voronoi图加随机扰动生成的。生态学和动物行为研究动物领地的划分模型每个个体占一块地盘跟Voronoi图几乎一模一样。最近邻查找与路径规划机器人导航里快速找最近目标点用Voronoi图做空间划分能大幅缩短搜索时间。适合谁学做科研数据处理的研究生、搞空间分析的工程师、学计算几何的本科生甚至是有兴趣的地理学爱好者。只要你手里有一堆坐标点想知道这些点在空间上怎么“瓜分地盘”Voronoi图就是你要的工具。2. Matlab里跟Voronoi相关的函数到底该选哪个Matlab原生支持Voronoi图这一点比Python需要装scipy.spatial.Voronoi要省心。但用哪个函数取决于你想干什么——画个图看看还是拿数据做计算分析。我在实际中用下来主要涉及三个函数各有定位。2.1 voronoi(x,y)画图最快数据有限这是最直接的画图函数输入两组坐标向量直接出图x rand(1,20) * 100; y rand(1,20) * 100; voronoi(x, y);三行代码图就出来了。这个函数还有带返回值的版本返回的是Voronoi边的端点坐标[vx, vy] voronoi(x, y);这里vx和vy是2×m的矩阵每一列代表一条边的两个端点坐标。注意它返回的只是线段不是完整的多边形区域。这意味着它适合快速可视化但不适合做面积计算、拓扑分析这类后续操作。2.2 voronoin(P)数据最全核心主力这是我最常用的函数。输入一个n×2的坐标矩阵P返回顶点矩阵V和单元索引元胞数组C[V, C] voronoin(P);V是k×2的顶点坐标矩阵每一行是一个Voronoi顶点的坐标。C是一个n×1的元胞数组C{i}存的是第i个种子点对应的Voronoi单元按顺序经过的顶点索引——注意是索引不是坐标要查坐标得用V(C{i}, 1)和V(C{i}, 2)。这里有一个很关键、新手必坑的细节如果某个种子点位于凸包边界上它的Voronoi单元会延伸到无穷远此时C{i}的第一个元素是1而V(1,:)在Matlab中被定义为无穷远点[Inf Inf]。后面算面积的时候只要发现C{i}的第一个元素是1基本可以判定这个单元是开放的不能直接算面积。2.3 polybnd_voronoi边界裁剪工程必备原生voronoin算出来的无限延伸区域在实际工程里很头疼——你研究的是一个100×100的研究区结果边界上的点到图外去了这不合理。所以我在做正经项目时90%的情况会用File Exchange上的第三方函数polybnd_voronoi。这个函数的核心能力是在给定边界多边形比如矩形研究区边界内裁剪Voronoi图让所有单元都被限制在边界之内没有无限延伸问题边界处的单元也能完整闭合。函数的调法大致是[vx, vy] polybnd_voronoi(x, y, bdry_xy);其中bdry_xy是边界多边形的顶点坐标按顺序排列成闭合多边形。返回的vx和vy是裁剪后的Voronoi边线段端点用它画图就是完整闭合的研究区划分。还有个进阶版本调用方式能直接返回裁剪后每个单元的多边形顶点方便我直接算面积、做统计。这一点在做定量分析时太重要了后面实操环节我详细讲。3. 从零开始的完整实操Voronoi图生成与数据提取3.1 第一步准备种子点数据做任何空间分析第一步都是先把种子点弄干净。我习惯用固定的随机种子保证每次跑出来的结果一样方便调参和复现% 生成30个随机种子点分布在100×100的研究区内 rng(42); % 固定随机种子保证结果可复现 num 30; x rand(num,1) * 100; y rand(num,1) * 100; P [x, y]; % 组装成voronoin需要的输入格式如果你的种子点来自真实业务数据比如充电桩坐标、基站经纬度投影坐标记得先检查有没有重复点、有没有超出研究区的异常点。这两类脏数据会在后面引发非常诡异的问题后面第4节详述。3.2 第二步画图与数据提取双轨并行先上最核心的代码直接能跑% 基础可视化 figure(Color,w); voronoi(x,y); axis equal; grid on; xlim([0 100]); ylim([0 100]); title(基础Voronoi图);注意axis equal这行不能省。如果不加坐标轴比例不一致图形会被拉伸Voronoi图看起来就会变形垂直的边可能看起来不是垂直的影响你对结果直观判断。但如果要做数据分析光画图不够必须拿数据。用voronoin提取拓扑信息% 提取Voronoi图顶点和单元拓扑 [V, C] voronoin(P); % 查看前三个单元的顶点索引 disp(C(1:3));C{i}里的索引顺序是逆时针环绕的这直接决定了后面用patch填色、用polyarea算面积时不会出现自相交的混乱图形。Matlab在这点上的设计是很贴心的但前提是你知道它有序。3.3 第三步在边界上裁剪得到真正闭合的单元原生voronoin画出来的整个Voronoi图四周是发散出去的开放区域。研究区通常限定在一个矩形或任意多边形范围内所以需要裁剪。我用得最多的方案是polybnd_voronoi给一个矩形边界就能把所有开放单元收拢% 定义矩形研究区边界逆时针闭合 bdry [0 0; 100 0; 100 100; 0 100; 0 0]; % 调用polybnd_voronoi计算裁剪后的Voronoi边 [vx, vy] polybnd_voronoi(x, y, bdry); % 绘制裁剪后的Voronoi图 figure(Color,w); plot(vx, vy, b-, LineWidth, 1.2); hold on; plot(x, y, ro, MarkerFaceColor, r, MarkerSize, 6); axis equal; xlim([0 100]); ylim([0 100]); grid on; title(边界裁剪后的Voronoi图);这一段完成后每个种子点都被一个闭合的多边形围住而且所有多边形都落在研究区内部。这个形态才是做土地利用分析、服务范围统计时想要的结果。3.4 第四步计算每个单元的面积与服务范围统计有了裁剪后的Voronoi图面积计算就有意义了。我刚说polybnd_voronoi的进阶版本能返回裁剪后的单元多边形这里用Matlab自带的polyarea就能逐块算面积% 如果polybnd_voronoi返回裁剪后的顶点和单元索引 % 假设返回格式为 [vx, vy, bvx, bvy]其中bvx/bvy是裁剪后单元多边形坐标 % 下面用原生顶点数据做面积统计示例注意判断开放单元 areas zeros(num, 1); for i 1:num if any(C{i} 1) % 开放单元面积记为NaN表示无法直接计算 areas(i) NaN; else % 闭合单元用polyarea计算面积 areas(i) polyarea(V(C{i}, 1), V(C{i}, 2)); end end % 查看面积统计 fprintf(平均单元面积: %.2f\n, mean(areas, omitnan)); fprintf(最大单元面积: %.2f\n, max(areas)); fprintf(最小单元面积: %.2f\n, min(areas));这段代码跑完每个种子点对应的服务面积一目了然。实际项目中我还会把面积数据关联回原始业务表比如结合每个充电桩的功率、周边人口密度算加权服务覆盖率。这是Voronoi图最有价值的应用场景之一——把几何划分和业务指标打通。4. 实测中踩过的坑Voronoi图常见问题与排查4.1 无限顶点问题边界种子点的开放单元这是新手最常踩的坑。当你用voronoin时只要种子点位于整组点集的凸包边界上它的Voronoi单元就会向外无限延伸反映在C{i}里就是第一个元素是1。我之前有个同事拿着一组24个基站的数据算覆盖面积没检查开放单元就直接调polyarea跑出来一堆荒谬的负数面积他还以为算法有问题排查了一下午。解决办法就是在循环里加开放单元判断——if any(C{i} 1)。如果是开放单元要么跳过要么用polybnd_voronoi裁剪后再算。我个人的建议是做可视化的时候用voronoin没问题做面积统计时必须裁剪或者至少把开放单元单独标注出来避免统计数据被污染。4.2 顶点顺序错乱导致的多边形异常正常情况下C{i}里的顶点索引是按逆时针顺序排列的直接拿去patch或polyarea都行。但如果你手动处理过顶点顺序或者从某些第三方库导入数据顺序一旦变乱画出来的多边形就是个打结的线团面积计算也会出错。排查方法很简单随便取一个单元把C{i}和V(C{i},:)打出来看看手工连线画一画。如果发现顺序不对用sort函数结合角度排序可以修复但更保险的做法是保持原生数据不动所有下游操作都在原始C和V基础上做。4.3 种子点重合或共线种子点完全重合会让Voronoi图退化Matlab可能直接报错或者生成一个面积为0的畸变单元。共线更隐蔽——如果好几个点精确落在同一条直线上Voronoi图的边会出现共线退化图形呈锯齿状运行时不报错但结果不美观。4.4 voronoi图形显示不完整坐标轴比例陷阱别看这个问题小我见过不止一个人卡在这里。如果画voronoi图时忘了axis equal图形会被拉伸Voronoi图的边看起来就不垂直、不平行甚至会让人觉得算错了。实际上数据没错是坐标轴比例失真。加了axis equal后图形比例恢复正常边界也严丝合缝。这是一个典型的“图形渲染问题”被误认为是“算法问题”的场景。4.5 第三方函数安装与版本兼容polybnd_voronoi是在File Exchange上的函数下载后要把m文件放到当前工作目录或MATLAB路径下。有朋友遇到过下载后运行时提示“未定义函数”原因往往是路径没加进MATLAB。用addpath命令手动加一下即可addpath(你存放函数的路径);同时要注意不同Matlab版本对函数语法的兼容性老代码在新版本尤其是R2023b之后偶发报错基本都能在MathWorks官方文档的Release Notes里查到原因。5. 进阶玩法从“画个图”到“空间统计出图”5.1 按面积/类别给Voronoi单元上色拿到每个单元的面积后下一步就是把结果可视化。我常用的方式是用patch函数上色颜色映射服务面积大小这样一眼就能看出哪些区域覆盖不足figure(Color,w); hold on; for i 1:num if ~any(C{i} 1) % 用面积作为颜色映射的输入 patch(Faces, C{i}, Vertices, V, ... FaceColor, [0.2 0.6 0.9], ... EdgeColor, k, LineWidth, 0.8); end end plot(x, y, ro, MarkerFaceColor, r, MarkerSize, 6); axis equal; grid on;如果想按面积渐变着色可以在循环里给每个patch的FaceColor设置一个和面积成比例的值再搭配colormap来映射。5.2 三维Voronoi能玩吗Matlab的voronoin其实支持三维输入返回的是三维顶点和三维单元。但说实话三维Voronoi图的可视化在Matlab里做得不算友好出图效果一般。我个人的建议是如果你只是想做三维空间划分可视化用Python的scipy.spatial.Voronoi加matplotlib或者ParaView这类专业软件效果会好很多。Matlab的生是在二维数据和二维可视化上不必硬上三维。5.3 权重Voronoi图当每个点的“势力”不一样时标准的Voronoi图假设每个种子点的权重相同服务范围只取决于距离。但现实中并非如此——一个大功率充电桩的服务范围肯定比小功率的大一家旗舰店的辐射半径肯定比普通店大。这时就要用加权Voronoi图。Matlab原生没有直接实现加权Voronoi图但可以自己写。最常用的近似方法是用一个迭代求解器将每个种子点赋予权重通过优化划分边界逼近加权Voronoi图另一个思路在图像域做逐像素分类对所有像素点比较“距离/权重”取最小值归类。实测下来逐像素方法在几百个种子点级别完全可跑就是把每个像素当作一个数据点比较距离代码几十行效果很直观适合科研成果展示。5.4 结合地图数据的落地实践最后再说一个真实项目中常见的做法如果你手上是经纬度坐标想叠加到地图底图上做服务区展示先把经纬度用projfwd或geodetic2ecef等工具投影到平面坐标中国区域常用UTM投影或高斯-克吕格投影再用投影坐标做Voronoi图。得出的多边形再反投影回经纬度就能叠加到地图引擎上展示。这一步别省——直接用经纬度做Voronoi在数学上是不成立的因为球面上的测地距离不等于平面欧氏距离算出来的Voronoi边在地图上会偏差得离谱。从我个人的经验看Voronoi图的价值从来不在“能画出来”而在它帮你把空间划分问题转化为可量化的几何计算。不管是算服务范围、做设施布局优化还是分析空间分布规律只要你手里有一组坐标点Voronoi图就是那把最趁手的工具。Matlab做这件事的性价比极高原生的两个函数加上一个裁剪函数就能覆盖从快速出图到精细分析的全部场景。如果你在实际项目里跑出了奇怪的结果优先按上面第4节列的几个方向排查开放单元、顶点顺序、坐标轴比例、重合点八成问题都出在这几处。本文还有配套的精品资源点击获取

相关新闻

2026/9/2 5:54:10

Graph Engineering实战:将SOP建模为图,让Agent自动执行

最近在做一个内部告警机器人时,碰到了老问题:业务方给的 SOP 写得清清楚楚,但交给 Agent 执行时,要么顺序写死没法处理分支,要么改一条流程要翻代码找半天。后来换了个思路,把 SOP 直接建模成 graph&#x…

2026/9/2 5:54:10

绝区零搜打撤雷维普高效刷取:单局稳定2.5M收益思路拆解

绝区零搜打撤“雷维普”高效刷取笔记:单局稳定 2.5M 收益的思路拆解最近在《绝区零》的“搜打撤”模式里,很多玩家一直在找一套效率高、翻车率低、操作门槛又不算太高的阵容。试过几套热门配队之后,我个人比较推荐“雷维普”这个组合&#xf…

2026/9/2 5:54:10

OpenClaw实践:智能体自举开发与Skill机制全解析

当"用自家智能体开发自家智能体"这件事从口号变成团队的工作方式,它带来的冲击不只是效率提升,而是整个软件开发链路正在被重写。这是我在整理 OpenClaw 相关资料时最强烈的感触:这个项目之所以值得关注,不是因为又多了…

2026/9/2 6:04:10

Altium Designer中AMS1117-3.3V电源模块的完整集成库与模块化设计实践

简介:这是一份面向嵌入式硬件工程师、电子专业学生及Altium Designer初学者的3.3V线性稳压电源模块设计参考资源,基于经典AMS1117-3.3芯片构建,解决小功率数字电路系统中稳定低压供电的设计需求,适用于开发板供电、传感器模块电源…

2026/9/2 6:04:10

C++ : 智能指针

C++ 智能指针专题详解 智能指针是C++11引入的、用来解决裸指针内存管理痛点的核心工具,也是现代C++面试中出现频率最高的话题之一。本文从"为什么需要它"讲起,逐步深入到shared_ptr控制块的底层实现,最后覆盖实际工程中最容易踩的坑。 目录 为什么需要智能指针 RAII思…

2026/9/2 6:04:10

高端局撞车国服绝活哥:从BP到团战的四阶段拆解战术

最近在《王者荣耀》的国服晋级赛里,我遇到了一个让所有打野玩家都心头一紧的名字——世一云缨,子默。那一瞬间,我脑子里只有一个念头:这把,能赢吗?这不仅仅是一场普通的排位赛。对于冲击国服称号的玩家来说…

2026/9/2 6:04:10

AI入门项目拆解:从图像情绪分析看深度学习实践全流程

简介:本资源是面向高校《人工智能导论》课程学生的期末大作业完整交付包,聚焦基于图像的情绪识别这一典型AI应用任务,覆盖数据预处理、CNN/VGG/ResNet多模型实现与对比、人脸检测(Haar级联)、可视化分析及视频流实时推…

2026/9/1 16:02:17

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/1 8:27:47

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/1 7:04:43

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/2 0:03:41

单片机毕业设计-基于单片机与蓝牙通讯的输液状态监测终端设计与开发 基于 STM32 或 51 单片机的液位‑滴速‑温度多参数输液监护装置设计(024005)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/9/2 0:03:41

DeepSeek字幕翻译实战:从API调用到批量SRT转中文的完整方案

这次我们来看一个很实用的 DeepSeek 落地场景:用 DeepSeek 把英文视频字幕自动翻译成中文。具体案例是《恶魔君》1989 年第 28 集的英转中字幕任务,标题写得很直白,但背后其实是一整套可以复用的技术流程:字幕解析、模型调用、批量…

2026/9/2 0:03:41

用Python搭建搞笑语音助手:从语音识别到语音合成全教程

当你家里摆着一台天猫精灵,却总希望语音助手偶尔“不正经”一点,不用官方腔回答问题,而是张口就接几句搞笑段子,会是什么体验?我最近动手验证了一下这个想法——没有去改装任何市面上现有的智能音箱,而是直…

2026/9/2 1:15:22

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/2 1:15:22

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/2 1:15:20

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…