由角点定义的边界框对象的嵌套属性

通常,搅拌器脚本必须从 3D 点集合计算包围边界框,例如将默认搅拌器立方体边界框作为输入,


coords = np.array(

     [[-1.  1. -1.],

      [-1.  1.  1.],

      [ 1. -1. -1.],

      [ 1. -1.  1.],

      [ 1.  1. -1.],

      [ 1.  1.  1.]]

 )


bfl = coords.min(axis=0)

tbr = coords.max(axis=0)


G  = np.array((bfl, tbr)).T

bbox_coords = [i for i in itertools.product(*G)]

例如,边界框坐标将是相同顺序的立方体坐标


寻找一些Python“迭代魔法”,使用上面的和("left", "right"), ("front", "back"),("top", "bottom"),来制作一个辅助类


>>> bbox = BBox(bfl, tbr)

>>> bbox.bottom.front.left

(-1, -1, -1)


>>> bbox.top.front

(0, -1, 1)


>> bbox.bottom

(0, 0, -1)

即角顶点、边的中心、矩形的中心。(1、2 或 4 个角的平均总和)在搅拌机中,顶部为 +Z,前面为 -Y。


最初是在考虑用静态计算值填充嵌套字典之类的东西


d = {

    "front" : {

        "co" : (0, -1, 0),

        "top" : {

            "co" : (0, -1, 1),

            "left" : {"co" : (-1, -1, 1)},

            }

        }   

    }

通常,搅拌器脚本必须从 3D 点集合计算包围边界框,例如将默认搅拌器立方体边界框作为输入,


coords = np.array(

     [[-1.  1. -1.],

      [-1.  1.  1.],

      [ 1. -1. -1.],

      [ 1. -1.  1.],

      [ 1.  1. -1.],

      [ 1.  1.  1.]]

 )


bfl = coords.min(axis=0)

tbr = coords.max(axis=0)


G  = np.array((bfl, tbr)).T

bbox_coords = [i for i in itertools.product(*G)]

例如,边界框坐标将是相同顺序的立方体坐标


寻找一些Python“迭代魔法”,使用上面的和("left", "right"), ("front", "back"),("top", "bottom"),来制作一个辅助类


>>> bbox = BBox(bfl, tbr)

>>> bbox.bottom.front.left

(-1, -1, -1)


>>> bbox.top.front

(0, -1, 1)


>> bbox.bottom

(0, 0, -1)

即角顶点、边的中心、矩形的中心。(1、2 或 4 个角的平均总和)在搅拌机中,顶部为 +Z,前面为 -Y。


最初是在考虑用静态计算值填充嵌套字典之类的东西


d = {

    "front" : {

        "co" : (0, -1, 0),

        "top" : {

            "co" : (0, -1, 1),

            "left" : {"co" : (-1, -1, 1)},

            }

        }   

    }


慕森王
浏览 107回答 3
3回答

牧羊人nacy

这是两个相似的版本。两者的想法都是,您始终返回一个BBox对象,并且仅更改一个变量x ,该变量指示您通过left, , ... 指定的尺寸。最后,您有一个用于计算剩余角的中心的right函数。x第一种方法使用函数,因此您必须调用它们bbox.bottom().front().left().c()。这里的主要区别在于并非所有组合toptop lefttop righttop left front...在创建对象时计算,但仅在调用它们时计算。import numpy as npimport itertoolsclass BBox:&nbsp; &nbsp; """&nbsp; &nbsp; ("left", "right"), -x, +x&nbsp; &nbsp; ("front", "back"), -y, +y&nbsp; &nbsp; ("bottom", "top"), -z, +z&nbsp; &nbsp; """&nbsp; &nbsp; def __init__(self, bfl, tbr):&nbsp; &nbsp; &nbsp; &nbsp; self.bfl = bfl&nbsp; &nbsp; &nbsp; &nbsp; self.tbr = tbr&nbsp; &nbsp; &nbsp; &nbsp; self.g = np.array((bfl, tbr)).T&nbsp; &nbsp; &nbsp; &nbsp; self.x = [[0, 1], [0, 1], [0, 1]]&nbsp; &nbsp; def c(self):&nbsp; # get center coordinates&nbsp; &nbsp; &nbsp; &nbsp; return np.mean([i for i in itertools.product(*[self.g[i][self.x[i]] for i in range(3)])], axis=0)&nbsp; &nbsp; def part(self, i, xi):&nbsp; &nbsp; &nbsp; &nbsp; assert len(self.x[i]) == 2&nbsp; &nbsp; &nbsp; &nbsp; b2 = BBox(bfl=self.bfl, tbr=self.tbr)&nbsp; &nbsp; &nbsp; &nbsp; b2.x = self.x.copy()&nbsp; &nbsp; &nbsp; &nbsp; b2.x[i] = [xi]&nbsp; &nbsp; &nbsp; &nbsp; return b2&nbsp; &nbsp; def left(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.part(i=0, xi=0)&nbsp; &nbsp; def right(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.part(i=0, xi=1)&nbsp; &nbsp; def front(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.part(i=1, xi=0)&nbsp; &nbsp; def back(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.part(i=1, xi=1)&nbsp; &nbsp; def bottom(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.part(i=2, xi=0)&nbsp; &nbsp; def top(self):&nbsp; &nbsp; &nbsp; &nbsp; return self.part(i=2, xi=1)bbox = BBox(bfl=[-1, -1, -1], tbr=[1, 1, 1])>>> bbox.bottom().front().left().c()(-1, -1, -1)>>> bbox.top().front().c()(0, -1, 1)>>> bbox.bottom().c()(0, 0, -1)第二种方法使用本身就是BBox对象的属性。当您取消注释函数中的 print 语句时,init您可以了解构造过程中发生的所有递归调用。因此,虽然查看这里发生的情况可能会更复杂,但访问属性时会更方便。class BBox:&nbsp; &nbsp; def __init__(self, bfl, tbr, x=None):&nbsp; &nbsp; &nbsp; &nbsp; self.bfl = bfl&nbsp; &nbsp; &nbsp; &nbsp; self.tbr = tbr&nbsp; &nbsp; &nbsp; &nbsp; self.g = np.array((bfl, tbr)).T&nbsp; &nbsp; &nbsp; &nbsp; self.x = [[0, 1], [0, 1], [0, 1]] if x is None else x&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; # print(self.x)&nbsp; # Debugging&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; self.left = self.part(i=0, xi=0)&nbsp; &nbsp; &nbsp; &nbsp; self.right = self.part(i=0, xi=1)&nbsp; &nbsp; &nbsp; &nbsp; self.front = self.part(i=1, xi=0)&nbsp; &nbsp; &nbsp; &nbsp; self.back = self.part(i=1, xi=1)&nbsp; &nbsp; &nbsp; &nbsp; self.bottom = self.part(i=2, xi=0)&nbsp; &nbsp; &nbsp; &nbsp; self.top = self.part(i=2, xi=1)&nbsp; &nbsp; def c(self):&nbsp; # get center coordinates&nbsp; &nbsp; &nbsp; &nbsp; return np.mean([i for i in itertools.product(*[self.g[i][self.x[i]]&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for i in range(3)])], axis=0)&nbsp; &nbsp; def part(self, i, xi):&nbsp; &nbsp; &nbsp; &nbsp; if len(self.x[i]) < 2:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return None&nbsp; &nbsp; &nbsp; &nbsp; x2 = self.x.copy()&nbsp; &nbsp; &nbsp; &nbsp; x2[i] = [xi]&nbsp; &nbsp; &nbsp; &nbsp; return BBox(bfl=self.bfl, tbr=self.tbr, x=x2)bbox = BBox(bfl=[-1, -1, -1], tbr=[1, 1, 1])>>> bbox.bottom.front.left.c()(-1, -1, -1)您还可以在构造函数的末尾添加类似的内容,以删除无效的属性。(以防止类似的事情bbox.right.left.c())。它们None以前是,但AttributeError可能更合适。&nbsp; &nbsp;def __init__(self, bfl, tbr, x=None):&nbsp; &nbsp; &nbsp; &nbsp;...&nbsp; &nbsp; &nbsp; &nbsp;for name in ['left', 'right', 'front', 'back', 'bottom', 'top']:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if getattr(self, name) is None:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;delattr(self, name)你也可以添加一个__repr__()方法:&nbsp; &nbsp; def __repr__(self):&nbsp; &nbsp; &nbsp; &nbsp; return repr(self.get_vertices())&nbsp; &nbsp; def get_vertices(self):&nbsp; &nbsp; &nbsp; &nbsp; return [i for i in itertools.product(*[self.g[i][self.x[i]]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for i in range(3)])]&nbsp; &nbsp; def c(self):&nbsp; # get center coordinates&nbsp; &nbsp; &nbsp; &nbsp; return np.mean(self.get_vertices(), axis=0)bbox.left.front# [(-1, -1, -1), (-1, -1, 1)]bbox.left.front.c()# array([-1., -1.,&nbsp; 0.])编辑一段时间后回到这个问题后,我认为最好只添加相关属性而不添加全部,然后删除其中一半。所以我能想到的最紧凑/最方便的类是:class BBox:&nbsp; &nbsp; def __init__(self, bfl, tbr, x=None):&nbsp; &nbsp; &nbsp; &nbsp; self.bfl, self.tbr = bfl, tbr&nbsp; &nbsp; &nbsp; &nbsp; self.g = np.array((bfl, tbr)).T&nbsp; &nbsp; &nbsp; &nbsp; self.x = [[0, 1], [0, 1], [0, 1]] if x is None else x&nbsp; &nbsp; &nbsp; &nbsp; for j, name in enumerate(['left', 'right', 'front', 'back', 'bottom', 'top']):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; temp = self.part(i=j//2, xi=j%2)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if temp is not None:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setattr(self, name, temp)&nbsp; &nbsp; def c(self):&nbsp; # get center coordinates&nbsp; &nbsp; &nbsp; &nbsp; return np.mean([x for x in itertools.product(*[self.g[i][self.x[i]]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for i in range(3)])], axis=0)&nbsp; &nbsp; def part(self, i, xi):&nbsp; &nbsp; &nbsp; &nbsp; if len(self.x[i]) == 2:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x2, x2[i] = self.x.copy(), [xi]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return BBox(bfl=self.bfl, tbr=self.tbr, x=x2)

一只斗牛犬

这是使用迭代方法创建字典的另一个解决方案:import numpy&nbsp;import itertoolsdirections = ['left', 'right', 'front', 'back', 'bottom', 'top']dims = np.array([&nbsp; 0,&nbsp; &nbsp; &nbsp; &nbsp;0,&nbsp; &nbsp; &nbsp; &nbsp;1,&nbsp; &nbsp; &nbsp; 1,&nbsp; &nbsp; &nbsp; &nbsp; 2,&nbsp; &nbsp; &nbsp;2])&nbsp; # xyzdef get_vertices(bfl, tbr, x):&nbsp; &nbsp; g = np.array((bfl, tbr)).T&nbsp; &nbsp; return [v for v in itertools.product(*[g[ii][x[ii]] for ii in range(3)])]bfl = [-1, -1, -1]tbr = [1, 1, 1]d = {}for i in range(6):&nbsp; &nbsp; x = [[0, 1], [0, 1], [0, 1]]&nbsp; &nbsp; x[i//2] = [i % 2]&nbsp; # x[dim[i] = min or max&nbsp;&nbsp;&nbsp; &nbsp; d_i = dict(c=np.mean(get_vertices(bfl=bfl, tbr=tbr, x=x), axis=0))&nbsp; &nbsp; for j in np.nonzero(dims != dims[i])[0]:&nbsp; &nbsp; &nbsp; &nbsp; x[j//2] = [j % 2]&nbsp; &nbsp; &nbsp; &nbsp; d_ij = dict(c=np.mean(get_vertices(bfl=bfl, tbr=tbr, x=x), axis=0))&nbsp; &nbsp; &nbsp; &nbsp; for k in np.nonzero(np.logical_and(dims != dims[i], dims != dims[j]))[0]:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; x[k//2] = [k % 2]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; d_ij[directions[k]] = dict(c=np.mean(get_vertices(bfl=bfl, tbr=tbr, x=x), axis=0))&nbsp; &nbsp; &nbsp; &nbsp; d_i[directions[j]] = d_ij&nbsp; &nbsp; d[directions[i]] = d_id# {'left': {'c': array([-1.,&nbsp; 0.,&nbsp; 0.]),#&nbsp; &nbsp; 'front': {'c': array([-1., -1.,&nbsp; 0.]),#&nbsp; &nbsp; &nbsp; 'bottom': {'c': array([-1., -1., -1.])},#&nbsp; &nbsp; &nbsp; 'top': {'c': array([-1., -1.,&nbsp; 1.])}},#&nbsp; &nbsp; 'back': {'c': array([-1.,&nbsp; 1.,&nbsp; 1.]),#&nbsp; &nbsp; &nbsp; 'bottom': {'c': array([-1.,&nbsp; 1., -1.])},#&nbsp; &nbsp; &nbsp; 'top': {'c': array([-1.,&nbsp; 1.,&nbsp; 1.])}},&nbsp;#&nbsp; &nbsp;....您可以将其与链接的问题结合起来,通过 访问字典的键d.key1.key2。

小怪兽爱吃肉

我到了哪里了。以某种方式添加了这个作为答案,以更好地解释我的问题循环遍历立方体的 8 个顶点,将 3 个名称与每个有效角相匹配。“swizzle”是构成角的三个轴方向的排列。直接输入自嵌套字典d[i][j][k] = value是创建它们的一种轻松方式。(pprint(d)下)高兴的是,从那里开始,它变得丑陋,一些鸭子打字从简单的 8 垂直真值表中获取元素索引。没有特殊原因,将返回生成类的方法作为包装器,但我没有这样使用它。import numpy as npimport pprintimport operatorfrom itertools import product, permutationsfrom functools import reducefrom collections import defaultdictclass NestedDefaultDict(defaultdict):&nbsp; &nbsp; def __init__(self, *args, **kwargs):&nbsp; &nbsp; &nbsp; &nbsp; super(NestedDefaultDict, self).__init__(NestedDefaultDict, *args, **kwargs)&nbsp; &nbsp; def __repr__(self):&nbsp; &nbsp; &nbsp; &nbsp; return repr(dict(self))def set_by_path(root, items, value):&nbsp; &nbsp; reduce(operator.getitem, items[:-1], root)[items[-1]] = valuedef create_bbox_swizzle(cls, dirx=("left", "right"), diry=("front", "back"), dirz=("bottom", "top")):&nbsp; &nbsp; d = NestedDefaultDict()&nbsp; &nbsp; data = {}&nbsp; &nbsp; for i, cnr in enumerate(product(*(dirx, diry, dirz))):&nbsp; &nbsp; &nbsp; &nbsp; vert = {"index": i}&nbsp; &nbsp; &nbsp; &nbsp; data[frozenset(cnr)] = i&nbsp; &nbsp; &nbsp; &nbsp; for perm in permutations(cnr, 3):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; set_by_path(d, perm, vert)&nbsp; &nbsp; pprint.pprint(d)&nbsp; &nbsp; def wire_up(names, d):&nbsp; &nbsp; &nbsp; &nbsp; class Mbox:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; @property&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; def co(self):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return self.coords[self.vertices].mean(axis=0)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; def __init__(self, coords):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.coords = np.array(coords)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; self.vertices = [v for k, v in data.items() if k.issuperset(names)]&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pass&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; def __repr__(self):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if len(names) == 1:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return f"<BBFace {self.vertices}/>"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; elif len(names) == 2:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return f"<BBEdge {self.vertices}/>"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; elif len(names) == 3:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return f"<BBVert {self.vertices}/>"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return "<BBox/>"&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; pass&nbsp; &nbsp; &nbsp; &nbsp; def f(k, v):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; def g(self):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return wire_up(names + [k], v)(self.coords)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return property(g)&nbsp; &nbsp; &nbsp; &nbsp; for k, v in d.items():&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if isinstance(v, dict):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setattr(Mbox, k, (f(k, v)))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; else:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setattr(Mbox, k, v)&nbsp; &nbsp; &nbsp; &nbsp; return Mbox&nbsp; &nbsp; return wire_up([], d)@create_bbox_swizzleclass BBox:&nbsp; &nbsp; def __init__(self, *coords, **kwargs):&nbsp; &nbsp; &nbsp; &nbsp; pass试驾:>>> bbox = BBox(coords)&nbsp; # used coords instead of corners>>> bbox.coarray([ 5.96046448e-08, -1.19209290e-07,&nbsp; 0.00000000e+00])>>> bbox.left.bottom<BBEdge [0, 2]/>>>> bbox.left.bottom.vertices[0, 2]>>> bbox.left.bottom.coarray([-1.00000036e+00, -1.19209290e-07,&nbsp; 0.00000000e+00])
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python