存储关于3d空间中的点的信息

时间:2009-05-26 14:17:04

标签: python data-structures 3d matrix numpy

我正在用Python编写一些代码(目前为止只是为了好玩),它将在3d空间中的每个点上存储一些数据。我基本上是在一个存储任意对象的3d矩阵对象之后,这些对象允许我做一些高级选择,例如:

  • 得到x = 1,y = 2,z = 3的点。
  • 获取y = 2的所有点。
  • 获得位置x = 1,y = 2,z = 3的3个单位内的所有点。
  • 获取point.getType()==“Foo”
  • 的所有点

在上述所有内容中,我需要最终得到某种输出,这些输出会给我空间中的原始位置,以及存储在该点的数据。

显然numpy可以做我想要的,但它似乎高度优化了科学计算,并且弄清楚如何获得我想要的数据到目前为止还没有找到我。

有没有更好的选择,还是我应该回到笨拙的墙上敲我的头? :)

编辑:更多信息前三个答案让我意识到我应该包括:我不担心性能,这纯粹是一个概念验证,我更喜欢干净的代码以获得良好的性能。我还将获得给定3d空间中每个点的数据,所以我猜一个备用矩阵是不好的?

8 个答案:

答案 0 :(得分:4)

这是另一种常见方法

class Point( object ):
    def __init__( self, x, y, z, data ):
        self.x, self.y, self.z = x, y, z
        self.data = data
    def distFrom( self, x, y, z )
        return math.sqrt( (self.x-x)**2 + (self.y-y)**2 + (self.z-z)**2 )

database = [ Point(x,y,z,data), Point(x,y,z,data), ... ]

让我们来看看你的用例。

得到x = 1,y = 2,z = 3的点。

[ p for p in database if (p.x, p.y, p.z) == ( 1, 2, 3 ) ]

获取y = 2的所有点。

[ p for p in database if p.y == 2 ]

将所有点置于位置x = 1,y = 2,z = 3的3个单位内。

[ p for p in database if p.distFrom( 1, 2, 3 ) <= 3.0 ]

获取所有点point.getType()==“Foo”

[ p for p in database if type(p.data) == Foo ]

答案 1 :(得分:3)

嗯......如果你希望真的填充这个空间,那么你可能最好使用密集的矩阵式结构,基本上是voxels

如果您不希望填写它,请查看更优化的内容。我首先看一下octrees,它们通常用于这样的事情。

答案 2 :(得分:1)

numpy的一个优点是它非常快, 例如计算8000x8000邻接矩阵的pagerank需要几毫秒。即使numpy.ndarray只接受数字,您也可以将数字/ id-object映射存储在外部哈希表中,即字典(再次是高度优化的数据结构)。

切片就像在python中列表切片一样简单:

>>> from numpy import arange

>>> the_matrix = arange(64).reshape(4, 4, 4)
>>> print the_matrix[0][1][2]
    6
>>> print the_matrix[0][1]
    [4 5 6 7]
>>> print the_matrix[0]
    [[ 0  1  2  3]
    [ 4  5  6  7]
    [ 8  9 10 11]
    [12 13 14 15]]

如果围绕某个核心矩阵和id-object-mapping散列包裹一些所需的函数(距离),则可以在短时间内运行应用程序。

祝你好运!

答案 3 :(得分:0)

您可以使用numpy中的切片执行前2个查询:

a = numpy.zeros((4, 4, 4))
a[1, 2, 3] # The point at x=1,y=2,z=3
a[:, 2, :] # All points where y=2

对于第三个,如果你的意思是“在半径3的范围内得到所有点并且以x = 1,y = 2,z = 3为中心”,你将必须编写一个自定义函数来做到这一点;如果你想要一个立方体,你可以进行切片,例如:

a[1:3, 1:3, 1:3] # The 2x2x2 array sliced from the center of 'a'

对于第四个查询,如果存储在数组中的唯一数据是单元格类型,则可以将其编码为整数:

FOO = 1
BAR = 2
a = numpy.zeros((4, 4, 4), dtype="i")
a[1, 2, 3] = FOO
a[3, 2, 1] = BAR
def filter(a, type_code):
    coords = []
    for z in range(4):
        for y in range(4):
            for x in range(4):
                if a[x, y, z] == type_code:
                    coords.append((x, y, z))
    return coords
filter(a, FOO) # => [(1, 2, 3)]
numpy看起来像是做你想要的好工具,因为数组在内存中会更小,可以在C中轻松访问(甚至更好,cython!)并且扩展切片语法将避免你编写代码。

答案 4 :(得分:0)

这是一种可行的方法。

每个点都是一个4元组(x,y,z,数据),您的数据库如下所示:

database = [ (x,y,z,data), (x,y,z,data), ... ]

让我们来看看你的用例。

得到x = 1,y = 2,z = 3的点。

[ (x,y,z,data) for x,y,z,data in database if (x,y,z) == (1,2,3) ]

获取y = 2的所有点。

[ (x,y,z,data) for x,y,z,data in database if y == 2 ]

将所有点置于位置x = 1,y = 2,z = 3的3个单位内。

[ (x,y,z,data) for x,y,z,data in database if math.sqrt((x-1)**2+(y-2)**2+(z-3)**2)<=3.0 ]

获取所有点point.getType()==“Foo”

[ (x,y,z,data) for x,y,z,data in database if type(data) == Foo ]

答案 5 :(得分:0)

When to use Binary Space Partitioning, Quadtree, Octree?

3d array imo毫无价值。特别是如果你的世界充满活力。您应该在BSP,四叉树或八叉树之间做出决定。 BSP会做得很好。由于你的世界是3d,你在分割bsp时需要平面,而不是线。

干杯!

修改

  

我也会为每一点提供数据   在给定的3d空间中,所以我猜一个   备用矩阵不好?

我想如果总是知道你的数据集有多大并且它永远不会改变,那就没关系,即如果有更多的点被添加到它,那么它又会超出界限。在这种情况下,您必须调整3d数组的大小。

答案 6 :(得分:0)

如果你想要一个标准库的相对简单的解决方案,那么使用带有x,y,z元组作为键的字典是另一种解决方案。

import math

#use indexing to get point at (1,2,3): points[(1,2,3)]
get_points(points, x=None, y=None, x=None):
    """returns dict of all points with given x,y and/or z values.  Call using keywords (eg get_points(points, x=3)"""
    filteredPoints = points.items()
    if x:
        filteredPoints = [p for p in filteredPoints if p[0][0] == x]
    if y:
        filteredPoints = [p for p in filteredPoints if p[0][1] == y]
    if z:
        filteredPoints = [p for p in filteredPoints if p[0][0] == x]
    return dict(filteredPoints)

get_point_with_type(points, type_):
    """returns dict of points with point.getType() == type_"""
    filteredPoints = points.items()
    return dict((position,data) for position,data in points.iterItems() if data.getType == type_)

get_points_in_radius(points,x,y,z,r):
    """Returns a dict of points within radius r of point (x,y,z)"""
    def get_dist(x1,y1,z1,x2,y2,z3):
        return math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)+(z1-z2)*(z1-z2))
    return dict((position,data) for position,data in points.iterItems() if get_dist(x,y,z, *position) <= r))

由于python引用,你可以改变返回词典中的“点”,并且原始点也会改变(我认为)。

答案 7 :(得分:-1)

这取决于系统的精确配置,但是从您给出的示例中使用的是整数和离散点,因此考虑Sparse Matrix数据结构可能是合适的。