建议计算多个凸2D多边形的交叉点
Suggestions to Compute the Intersetions of Multiple Convex 2D Polygons
我正在为任何可以快速计算N
2D多边形(投影凸Polyhedrons的凸壳)的交叉的任何最先进软件或方法钓鱼。M
2D多边形通常是N >> M
。N
可以按顺序或至少为1M多边形,而N
则以50k为单位。我现在搜索了一段时间,但是我一直想出下面显示的相同答案。
使用Boost和循环
- 计算多面体的投影(不是瓶颈)
- 计算上述多面体(瓶颈)的凸壳
- 计算预测的多面体和现有2D多边形(主要瓶颈)的交点。
此循环重复NK
次,其中通常为K << M
,而K
是与单个投影多面体相交的2D多边形的平均数量。这样做是为了减少计算数量。
问题是,如果我拥有N=262144
和M=19456
,则大约需要129秒(当多面角性读取时),必须进行大约300次。理想情况下,我想将计算时间减少到上述尺寸的大约1秒钟,因此我想知道某人是否可以指出一些可以提高效率的软件或文献。
[编辑]
@sehe的请求我要发布代码中最相关的部分。我还没有编译,所以这只是为了获得要点...该代码假设,有体素和像素,但是形状可以是任何东西。网格中的点的顺序可以是任何一个,但是这些点位于网格中的索引相同。
#include <boost/geometry/geometry.hpp>
#include <boost/geometry/geometries/point.hpp>
#include <boost/geometry/geometries/ring.hpp>
const std::size_t Dimension = 2;
typedef boost::geometry::model::point<float, Dimension, boost::geometry::cs::cartesian> point_2d;
typedef boost::geometry::model::polygon<point_2d, false /* is cw */, true /* closed */> polygon_2d;
typedef boost::geometry::model::box<point_2d> box_2d;
std::vector<float> getOverlaps(std::vector<float> & projected_grid_vx, // projected voxels
std::vector<float> & pixel_grid_vx, // pixels
std::vector<int> & projected_grid_m, // number of voxels in each dimension
std::vector<int> & pixel_grid_m, // number of pixels in each dimension
std::vector<float> & pixel_grid_omega, // size of the pixel grid in cm
int projected_grid_size, // total number of voxels
int pixel_grid_size) { // total number of pixels
std::vector<float> overlaps(projected_grid_size * pixel_grid_size);
std::vector<float> h(pixel_grid_m.size());
for(int d=0; d < pixel_grid_m.size(); d++) {
h[d] = (pixel_grid_omega[2*d+1] - pixel_grid_omega[2*d]) / pixel_grid_m[d];
}
for(int i=0; i < projected_grid_size; i++){
std::vector<float> point_indices(8);
point_indices[0] = i;
point_indices[1] = i + 1;
point_indices[2] = i + projected_grid_m[0];
point_indices[3] = i + projected_grid_m[0] + 1;
point_indices[4] = i + projected_grid_m[0] * projected_grid_m[1];
point_indices[5] = i + projected_grid_m[0] * projected_grid_m[1] + 1;
point_indices[6] = i + (projected_grid_m[1] + 1) * projected_grid_m[0];
point_indices[7] = i + (projected_grid_m[1] + 1) * projected_grid_m[0] + 1;
std::vector<float> vx_corners(8 * projected_grid_m.size());
for(int vn = 0; vn < 8; vn++) {
for(int d = 0; d < projected_grid_m.size(); d++) {
vx_corners[vn + d * 8] = projected_grid_vx[point_indices[vn] + d * projeted_grid_size];
}
}
polygon_2d proj_voxel;
for(int vn = 0; vn < 8; vn++) {
point_2d poly_pt(vx_corners[2 * vn], vx_corners[2 * vn + 1]);
boost::geometry::append(proj_voxel, poly_pt);
}
boost::geometry::correct(proj_voxel);
polygon_2d proj_voxel_hull;
boost::geometry::convex_hull(proj_voxel, proj_voxel_hull);
box_2d bb_proj_vox;
boost::geometry::envelope(proj_voxel_hull, bb_proj_vox);
point_2d min_pt = bb_proj_vox.min_corner();
point_2d max_pt = bb_proj_vox.max_corner();
// then get min and max indices of intersecting bins
std::vector<float> min_idx(projected_grid_m.size() - 1),
max_idx(projected_grid_m.size() - 1);
// compute min and max indices of incidence on the pixel grid
// this is easy assuming you have a regular grid of pixels
min_idx[0] = std::min( (float) std::max( std::floor((min_pt.get<0>() - pixel_grid_omega[0]) / h[0] - 0.5 ), 0.), pixel_grid_m[0]-1);
min_idx[1] = std::min( (float) std::max( std::floor((min_pt.get<1>() - pixel_grid_omega[2]) / h[1] - 0.5 ), 0.), pixel_grid_m[1]-1);
max_idx[0] = std::min( (float) std::max( std::floor((max_pt.get<0>() - pixel_grid_omega[0]) / h[0] + 0.5 ), 0.), pixel_grid__m[0]-1);
max_idx[1] = std::min( (float) std::max( std::floor((max_pt.get<1>() - pixel_grid_omega[2]) / h[1] + 0.5 ), 0.), pixel_grid_m[1]-1);
// iterate only over pixels which intersect the projected voxel
for(int iy = min_idx[1]; iy <= max_idx[1]; iy++) {
for(int ix = min_idx[0]; ix <= max_idx[0]; ix++) {
int idx = ix + iy * pixel_grid_size[0]; // `first' index of pixel corner point
polygon_2d pix_poly;
for(int pn = 0; pn < 4; pn++) {
point_2d pix_corner_pt(
pixel_grid_vx[idx + pn % 2 + (pn / 2) * pixel_grid_m[0]],
pixel_grid_vx[idx + pn % 2 + (pn / 2) * pixel_grid_m[0] + pixel_grid_size]
);
boost::geometry::append(pix_poly, pix_corner_pt);
}
boost::geometry::correct( pix_poly );
//make this into a convex hull since the order of the point may be any
polygon_2d pix_hull;
boost::geometry::convex_hull(pix_poly, pix_hull);
// on to perform intersection
std::vector<polygon_2d> vox_pix_ints;
polygon_2d vox_pix_int;
try {
boost::geometry::intersection(proj_voxel_hull, pix_hull, vox_pix_ints);
} catch ( std::exception e ) {
// skip since these may coincide at a point or line
continue;
}
// both are convex so only one intersection expected
vox_pix_int = vox_pix_ints[0];
overlaps[i + idx * projected_grid_size] = boost::geometry::area(vox_pix_int);
}
} // end intersection for
} //end projected_voxel for
return overlaps;
}
您可以创建多边形与边界框的比例:
这可以在计算上完成一次,以达到Avgerage Poly区域与BB比率R
常数。或者,您可以使用由其BB界定的圆来使用几何形状进行操作,因为您仅使用投影的多面体:
R = 0.0;
count = 0;
for (each poly) {
count++;
R += polyArea / itsBoundingBoxArea;
}
R = R/count;
然后计算边界框交点的求和。
Sbb = 0.0;
for (box1, box2 where box1.isIntersecting(box2)) {
Sbb += box1.intersect(box2);
}
然后:
Approximation = R * Sbb
如果允许凹入的polys,所有这些都不起作用。因为凹面poly可以占据不到它的边界框的1%。您仍然必须找到凸壳。
另外,如果您可以找到比其船体快的多边形区域,则可以使用实际计算的平均多个区域。这也将为您带来不错的近似值,同时避免Poly交叉点和包装。
hm,问题似乎类似于"碰撞检索" i游戏引擎。或"潜在可见的集合"。
尽管我对当前的最新目前了解不多,但我记得优化是将物体包裹在球体中,因为检查球体之间的重叠(或2D中的圆圈)确实很便宜。为了加快检查碰撞的检查,通常将对象放入搜索结构中(例如Sphere-Tree(2D情况下的Circle-Tree))。基本上将空间组织成层次结构,以快速进行重叠的查询。
基本上我的建议归结为:尝试查看碰撞检索的算法。
假设我假设您的意思是"交叉点"而不是交集。此外,M
和N
中的大多数单独的多数都不会同时重叠。如果此假设为true,则:
答案
使用2D游戏引擎完成操作的方法是拥有一个场景图,每个对象都有一个边界框。然后,将所有多边形根据界限通过边界框确定的位置放在Quadtree中的节点中。然后,任务变得平行,因为每个节点都可以分别处理以进行相交。
这是Quadtree的Wiki:
Quadtree Wiki
在3D中可以使用octree。
实际上,它甚至不必成为OCTREE。任何空间分区都可以获得相同的结果。您可以找到最大的小球分离(我们称其为S
)。并创建Say S/10
空间分区。然后,您将有10个单独的空间并行执行。它不仅是并发的,而且不再是M * N
时间
- 2D数组来自文本输入,中间有空格
- 将值指定给向量(2D)的向量中的某个位置
- 如何使用用户输入在C++中正确填充2D数组
- 如何在C++中检查2D数组中负值的输入验证
- 当我在main中声明了我的2d数组时,为什么我的程序会退出
- 计算缩放多边形的比例,得到给定的多边形面积
- 在 2D 向量中使用第三个 [ ] 有什么意义?
- 四边形的 2D 旋转
- 打印第二列时的2d字符矢量打印空间
- 将QGraphicsItem的移动区域限制在多边形区域内
- 如何将以逗号和空格分隔的整数读取到 2D 数组中?
- 如何在C++函数中声明静态 2D 数组?
- 我是 C++ 的初学者,我想知道如何在 2D 矢量中获取重复值
- 如何声明一个可以在整个程序中使用的全局 2d 3d 4d .. 数组(堆版本)变量?
- opengl glBegin(GL_LINES) 和 glBegin(GL_POINT) 在 2D 中不可视化点矢量
- 在C++中迭代 2D 容器的最干净方法
- 建议计算多个凸2D多边形的交叉点
- 在一个维度中调整 2D 多边形的大小
- 当标准测试失败时,用于查找点是否在2D多边形内的替代测试
- 在OpenGL中使用多边形绘制2D粗圆弧