- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我正在尝试找到一种在 Python 中计算二维幂图的方法。为此,我想利用一个事实 a 2d power diagram can be interpreted as the intersection of a regular 3d voronoi diagram with a plane .
随着SciPy Voronoi我可以计算 3d Voronoi 图的模块 - 是否可以将它与平面相交并将其转换为 2d 图?
最佳答案
SciPy 中还没有功率图功能。
将 3D Voronoi 图转换为 2D 功率图可能很困难,而且至少在 Python 中速度很慢。
为了解决这个问题,我开发了一个基于 CGAL 的 C++ 程序,然后可以用 Python 对其进行包装。
有了 Python 函数和 C++ 代码,可以使用以下方法生成功率图:
polys, bbox = GetPowerDiagram(pts)
如果电源图被裁剪到点云的边界框,结果如下所示:
如果它未被裁剪(但转换为有限表示):
以下代码自 02019-01-12 起使用 GCC 7.3.0、Python 3.6.7、CGAL 4.11 (1041101000) 运行。代码也可以在 Github 上获取 here .
#!/usr/bin/env python3
#Power Diagramer
#Author: Richard Barnes (rbarnes.org)
#!/usr/bin/env python3
import plumbum
import random
import shapely
import shapely.wkt
from matplotlib import pyplot as plt
from descartes import PolygonPatch
def GetPowerDiagram(points, ray_length=1000, crop=True):
"""Generates a power diagram of a set of points.
Arguments:
points - A list of points of the form `[(x,y,weight), (x,y,weight), ...]`
ray_length - The power diagram contains infinite rays. The direction vector
of those rays will be multiplied by `ray_length` and the ends
of the rays connected in order to form a finite representation
of the polygon
crop - If `True`, then the bounded representation above is cropped to
the bounding box of the point cloud
"""
powerd = plumbum.local["./power_diagramer.exe"]
#Format output for reading by power_diagramer.exe
points = [map(str,x) for x in points]
points = [' '.join(x) for x in points]
points = '\n'.join(points)
points = '{raylen}\n{crop}\n{points}'.format(
raylen = ray_length,
crop = 'CROP' if crop else 'NOCROP',
points = points
)
#Run the command
polygons = (powerd["-"] << points)()
#Get the output of `power_diagramer.exe`. It is in WKT format, one polygon per
#line.
polygons = polygons.split("\n")
polygons = [x.strip() for x in polygons]
polygons = [x for x in polygons if len(x)>0]
polygons = [shapely.wkt.loads(x) for x in polygons]
#Generate bounding box for ease in plotting
bbox = [x.bounds for x in polygons]
minx = min([x[0] for x in bbox])
miny = min([x[1] for x in bbox])
maxx = max([x[2] for x in bbox])
maxy = max([x[3] for x in bbox])
return polygons, (minx,miny,maxx,maxy)
POINT_COUNT = 100
pts = []
for i in range(POINT_COUNT):
x = random.uniform(0,100)
y = random.uniform(0,100)
weight = random.uniform(0,10)
pts.append((x,y,weight))
polys, (minx, miny, maxx, maxy) = GetPowerDiagram(pts, ray_length=1000, crop=True)
fig = plt.figure(1, figsize=(5,5), dpi=90)
ax = fig.add_subplot(111)
ax.set_xlim(minx,maxx)
ax.set_ylim(miny,maxy)
for poly in polys:
ax.add_patch(PolygonPatch(poly))
plt.show()
all:
#-frounding-math is GCC specific, but required for any CGAL code compiled with
#GCC
g++ -O3 power_diagram_lib.cpp -o power_diagramer.exe -Wall -lCGAL -lgmp -lgmpxx -lmpfr -frounding-math
生成的可执行文件名为 power_diagramer.exe
并放置在与 Python 脚本相同的目录中。
//Finds the cropped Voronoi diagram of a set of points and saves it as WKT
//Compile with: g++ -O3 main.cpp -o power_diagramer.exe -Wall -lCGAL -lgmp
//Author: Richard Barnes (rbarnes.org)
#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
#include <CGAL/Regular_triangulation_filtered_traits_2.h>
#include <CGAL/Regular_triangulation_adaptation_traits_2.h>
#include <CGAL/Regular_triangulation_adaptation_policies_2.h>
#include <CGAL/Regular_triangulation_2.h>
#include <CGAL/Voronoi_diagram_2.h>
#include <CGAL/Boolean_set_operations_2.h>
#include <CGAL/bounding_box.h>
#include <CGAL/Polygon_2.h>
#include <iostream>
#include <cstdint>
#include <string>
#include <memory>
typedef CGAL::Exact_predicates_exact_constructions_kernel K;
typedef CGAL::Regular_triangulation_2<K> RT;
typedef CGAL::Regular_triangulation_adaptation_traits_2<RT> AT;
typedef CGAL::Regular_triangulation_degeneracy_removal_policy_2<RT> DRP;
typedef CGAL::Voronoi_diagram_2<RT, AT, DRP> VD;
int main(int argc, char **argv){
if(argc!=2){
std::cerr<<"Synax: "<<argv[0]<<" <FILENAME>"<<std::endl;
std::cerr<<"<FILENAME> may be a file or '-'. The latter reads from stdin."<<std::endl;
std::cerr<<"File has the format:"<<std::endl;
std::cerr<<"<RAY_LENGTH>" <<std::endl;
std::cerr<<"<CROP/NOCROP>" <<std::endl;
std::cerr<<"<X> <Y> <WEIGHT>" <<std::endl;
std::cerr<<"<X> <Y> <WEIGHT>" <<std::endl;
std::cerr<<"..." <<std::endl;
std::cerr <<std::endl;
std::cerr<<"'RAY_LENGTH' is a multiplier that extends infinite rays"<<std::endl;
std::cerr<<"'CROP' will crop the power diagram to the bounding box of the input points"<<std::endl;
return -1;
}
std::string filename = argv[1];
//Output formatting
std::cout.precision(4); //Number of digits of decimal precision
std::cout.setf(std::ios::fixed); //Don't use scientific notation
//Used to convert otherwise infinite rays into looooong line segments by
//multiplying the components of the direction vector of a ray by this value.
int RAY_LENGTH = 1000;
//Create a pointer to the correct input stream
std::istream *fin;
if(filename=="-")
fin = &std::cin;
else
fin = new std::ifstream(filename);
std::string crop_string;
bool do_crop = false;
(*fin)>>RAY_LENGTH;
(*fin)>>crop_string;
if(crop_string=="CROP")
do_crop = true;
else if(crop_string=="NOCROP")
do_crop = false;
else {
std::cerr<<"Crop value must be 'CROP' or 'NOCROP'!"<<std::endl;
return -1;
}
//Read in points from the command line
RT::Weighted_point wp;
std::vector<RT::Weighted_point> wpoints;
while((*fin)>>wp)
wpoints.push_back(wp);
//Clean up the stream pointer
if(filename!="-")
delete fin;
//Create a Regular Triangulation from the points
RT rt(wpoints.begin(), wpoints.end());
rt.is_valid();
//Wrap the triangulation with a Voronoi diagram adaptor. This is necessary to
//get the Voronoi faces.
VD vd(rt);
//CGAL often returns objects that are either segments or rays. This converts
//these objects into segments. If the object would have resolved into a ray,
//that ray is intersected with the bounding box defined above and returned as
//a segment.
const auto ConvertToSeg = [&](const CGAL::Object seg_obj, bool outgoing) -> K::Segment_2 {
//One of these will succeed and one will have a NULL pointer
const K::Segment_2 *dseg = CGAL::object_cast<K::Segment_2>(&seg_obj);
const K::Ray_2 *dray = CGAL::object_cast<K::Ray_2>(&seg_obj);
if (dseg) { //Okay, we have a segment
return *dseg;
} else { //Must be a ray
const auto &source = dray->source();
const auto dsx = source.x();
const auto dsy = source.y();
const auto &dir = dray->direction();
const auto tpoint = K::Point_2(dsx+RAY_LENGTH*dir.dx(),dsy+RAY_LENGTH*dir.dy());
if(outgoing)
return K::Segment_2(
dray->source(),
tpoint
);
else
return K::Segment_2(
tpoint,
dray->source()
);
}
};
//Loop over the faces of the Voronoi diagram in some arbitrary order
for(VD::Face_iterator fit = vd.faces_begin(); fit!=vd.faces_end();++fit){
CGAL::Polygon_2<K> pgon;
//Edge circulators traverse endlessly around a face. Make a note of the
//starting point so we know when to quit.
VD::Face::Ccb_halfedge_circulator ec_start = fit->ccb();
//Find a bounded edge to start on
for(;ec_start->is_unbounded();ec_start++){}
//Current location of the edge circulator
VD::Face::Ccb_halfedge_circulator ec = ec_start;
//In WKT format each polygon must begin and end with the same point
K::Point_2 first_point;
do {
//A half edge circulator representing a ray doesn't carry direction
//information. To get it, we take the dual of the dual of the half-edge.
//The dual of a half-edge circulator is the edge of a Delaunay triangle.
//The dual of the edge of Delaunay triangle is either a segment or a ray.
// const CGAL::Object seg_dual = rt.dual(ec->dual());
const CGAL::Object seg_dual = vd.dual().dual(ec->dual());
//Convert the segment/ray into a segment
const auto this_seg = ConvertToSeg(seg_dual, ec->has_target());
pgon.push_back(this_seg.source());
if(ec==ec_start)
first_point = this_seg.source();
//If the segment has no target, it's a ray. This means that the next
//segment will also be a ray. We need to connect those two rays with a
//segment. The following accomplishes this.
if(!ec->has_target()){
const CGAL::Object nseg_dual = vd.dual().dual(ec->next()->dual());
const auto next_seg = ConvertToSeg(nseg_dual, ec->next()->has_target());
pgon.push_back(next_seg.target());
}
} while ( ++ec != ec_start ); //Loop until we get back to the beginning
if(do_crop){
//Find the bounding box of the points. This will be used to crop the Voronoi
//diagram later.
const CGAL::Bbox_2 bbox = CGAL::bbox_2(wpoints.begin(), wpoints.end());
//In order to crop the Voronoi diagram, we need to convert the bounding box
//into a polygon. You'd think there'd be an easy way to do this. But there
//isn't (or I haven't found it).
CGAL::Polygon_2<K> bpoly;
bpoly.push_back(K::Point_2(bbox.xmin(),bbox.ymin()));
bpoly.push_back(K::Point_2(bbox.xmax(),bbox.ymin()));
bpoly.push_back(K::Point_2(bbox.xmax(),bbox.ymax()));
bpoly.push_back(K::Point_2(bbox.xmin(),bbox.ymax()));
//Perform the intersection. Since CGAL is very general, it believes the
//result might be multiple polygons with holes.
std::list<CGAL::Polygon_with_holes_2<K>> isect;
CGAL::intersection(pgon, bpoly, std::back_inserter(isect));
//But we know better. The intersection of a convex polygon and a box is
//always a single polygon without holes. Let's assert this.
assert(isect.size()==1);
//And recover the polygon of interest
auto &poly_w_holes = isect.front();
pgon = poly_w_holes.outer_boundary();
}
//Print the polygon as a WKT polygon
std::cout<<"POLYGON ((";
for(auto v=pgon.vertices_begin();v!=pgon.vertices_end();v++)
std::cout<<v->x()<<" "<<v->y()<<", ";
std::cout<<pgon.vertices_begin()->x()<<" "<<pgon.vertices_begin()->y()<<"))\n";
}
return 0;
}
关于python - 从 3d 到 2d 的 Project Scipy Voronoi 图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27406557/
我有一个让我想起 Voronoi 的问题,但我希望我的变体能让我避免使用 Voronoi 算法,并更快地写一些东西。 这是我在 Paint 中制作的一个可怕的图像来说明我的问题: 假设我有一个 map
上午下午 或晚上。 # Reproducible data df % filter(years == i) # # plot % filter(years == i)
我正在生成一个简单的 2D Voronoi 曲面分割,使用 scipy.spatial.Voronoi功能。我使用点的随机二维分布(参见下面的 MCVE)。 我需要一种方法来遍历每个定义的区域(由 s
我现在花了很多时间试图从 scipy.spatial.Voronoi 图中获取边,但无济于事。这是主要文档: http://docs.scipy.org/doc/scipy-dev/reference
我正在使用 voronoi 镶嵌。我有不同的多边形代表分割中的区域。 下面的点用于绘制图中的曲面分割。 tessdata [,1] [,2] 1 -0.4960583 -0.35
我有一个可折叠的力导向布局,我从 here 中引用了它. 我修改了代码,在图中的每个节点后面添加了 Voronoi 单元。目前,它看起来像是在工作,因为我可以看到 Voronoi 单元格根据折叠状态出
我创建了一个无法正常工作的 voronoi 代码。 我真的想不出错误!!! 我调用的函数是: void Voronoi( const int NbPoints, const int h
给定 voronoi 边列表,如何在合理的时间内获得每个单元格的质心?请注意,我只有 Voronoi 图的边,但我必须确定质心。 Voronoi 图是给定 Delaunay 三角剖分构造的,因此三角剖
到目前为止,我有一个程序采用一组随机点、站点,并围绕这些点形成适当的 Voronoi 图,表示为角和边的图形。它还为我提供了 Delaunay 三角剖分作为另一个以所有站点为节点的图形(尽管我不知道这
我正在寻找一种简单的(如果存在的话)算法来查找球体表面上一组点的 Voronoi 图。源代码会很棒。我是 Delphi 人(是的,我知道...),但我也吃 C 代码。 最佳答案 2016 年 7 月更
我需要生成一个 Voronoi diagram围绕多边形内部的凹(非凸)。我在网上找过方法,但我一直无法弄清楚如何做到这一点。基本上,我生成点的凸包,计算对偶点并在这些点之间构建边缘网络。然而,当遇到
我正在尝试使用 scipy.spatial.Voronoi 计算 Voronoi 图每个区域的确切边界,前提是所有点都在预定义的多边形内。例如,使用此 documentation 中的示例. 如果我需
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 要求我们推荐或查找书籍、工具、软件库、教程或其他场外资源的问题对于 Stack Overflow 来说是
我正在使用 Voronoi 图进行图像处理 ( procedurally generated stippling )。 为了做到这一点,我需要创建一个元组(x,y 像素位置)列表(coords_wit
我有两个 geopandas 数据框 dfMd 和 centers。 dfMd 由多边形组成,而 centers 由点组成。 Here文件的链接。 f,ax=plt.subplots() dfMd.p
我正在使用 scipy.spatial用于 Voronoi 图的可视化。但是,这里使用的距离度量是欧几里得 (L2)。我正在我的 Voronoi 图上寻找一种曼哈顿 (L1) 度量方式。有没有一种简单
据我了解,R 缺少一种方法来以空间独占的方式缓冲多边形,以保留相邻多边形的拓扑结构。所以我正在试验一种生成原始多边形顶点的 voronoi 多边形的方法。除了 voronoi 生成中的明显错误外,结果
我一直在尝试为各州创建自定义区域。我想通过使用点的影响区域来填充状态图。 下图代表了我一直在尝试的东西。左图显示了点,我只想像右图一样填充所有区域。我使用了 Voronoi/Thiesen,但它在区域
我想弄清楚如何为两个不同的点绘制 Voronoi 图。 有人可以帮我吗。 谢谢 最佳答案 如我的图片所示,你应该只连接你的点,然后画一条穿过中心的线,与该线段正交。 关于draw - 如何绘制两个不同
我正在尝试在固定地理区域内为一组点创建 Voronoi 多边形(又名 Dirichlet 镶嵌或泰森多边形)。但是,我无法在 R 中找到一种将多边形绑定(bind)在 map 边界内的方法。我的主要目
我是一名优秀的程序员,十分优秀!