Для этой задачи я получил 8 вершин поля, которое мне нужно сжать, с заданным размером, который является целым числом, с которым мне нужно сжать каждую сторону. Например, если размер блока, который мне нужно уменьшить, равен 8 * 8 * 8, а размер сжатия равен 2, мне нужно вернуть список всех вершин 4 * 4 * 4 блоков, которые заполняют большой блок в трехмерная система координат.

Я думал о том, чтобы иметь цикл for, который работает в диапазоне размера блока, но я подумал, что если я захочу в конечном итоге разделить блок на гораздо больше блоков, которые будут меньше, и я хочу заполнить большой блок, то мне придется написать количество кода, который я не смог бы написать. Как получить этот список вершин без написания такого большого количества кода?

1
Jhonathan Mizrahi 3 Июл 2019 в 15:47

3 ответа

Лучший ответ

Решение с использованием NumPy, что позволяет легко манипулировать блоком.

Сначала я выбираю представление куба с началом координат и тремя векторами: единичный куб представлен orig=np.array([0,0,0]) и vects=np.array([[1,0,0],[0,1,0],[0,0,1]]).

Теперь функция numpy для генерации восьми вершин:

import numpy as np

def cube(origin,edges):
    for e in edges:
        origin = np.vstack((origin,origin+e))
    return origin


cube(orig,vects)

array([[0, 0, 0],
       [1, 0, 0],
       [0, 1, 0],
       [1, 1, 0],
       [0, 0, 1],
       [1, 0, 1],
       [0, 1, 1],
       [1, 1, 1]])

Затем другой, чтобы охватить мини-кубы в 3D:

def split(origin,edges,k):
    minicube=cube(origin,edges/k)
    for e in edges/k:
        minicube =np.vstack([minicube + i*e for i in range(k) ])
    return minicube.reshape(k**3,8,3) 


split (orig,vects,2)

array([[[ 0. ,  0. ,  0. ],
        [ 0.5,  0. ,  0. ],
        [ 0. ,  0.5,  0. ],
        [ 0.5,  0.5,  0. ],
        [ 0. ,  0. ,  0.5],
        [ 0.5,  0. ,  0.5],
        [ 0. ,  0.5,  0.5],
        [ 0.5,  0.5,  0.5]],
   ...

       [[ 0.5,  0.5,  0.5],
        [ 1. ,  0.5,  0.5],
        [ 0.5,  1. ,  0.5],
        [ 1. ,  1. ,  0.5],
        [ 0.5,  0.5,  1. ],
        [ 1. ,  0.5,  1. ],
        [ 0.5,  1. ,  1. ],
        [ 1. ,  1. ,  1. ]]])
0
B. M. 3 Июл 2019 в 15:13

Мой пример ниже будет работать с общим окном и предполагает целочисленные координаты.



    import numpy as np

    def create_cube(start_x, start_y, start_z, size):
        return np.array([
            [x,y,z]
            for z in [start_z, start_z+size]        
            for y in [start_y, start_y+size]
            for x in [start_x, start_x+size]
        ])

    def subdivide(box, scale):
        start =  np.min(box, axis=0)
        end = np.max(box, axis=0) - scale

        return np.array([
            create_cube(x, y, z, scale)
            for z in range(start[2], end[2]+1)
            for y in range(start[1], end[1]+1)
            for x in range(start[0], end[0]+1)
        ])

    cube = create_cube(1, 3, 2, 8)

Куб будет выглядеть так:


    array([[ 1,  3,  2],
           [ 9,  3,  2],
           [ 1, 11,  2],
           [ 9, 11,  2],
           [ 1,  3, 10],
           [ 9,  3, 10],
           [ 1, 11, 10],
           [ 9, 11, 10]])

Запуск следующего подразделения:



    subcubes = subdivide(cube, 2)

Функция subdivide создает nparray с формой: (343, 8, 3). Можно ожидать, что 343 субкуба будут равномерно перемещать куб 2x2 по кубу 8x8.

0
Joel Baumert 3 Июл 2019 в 15:56

Я не уверен, что вы этого хотите, но вот простой способ вычисления вершин в сетке с помощью NumPy:

import numpy as np

def make_grid(x_size, y_size, z_size, shrink_factor):
    n = (shrink_factor + 1) * 1j
    xx, yy, zz = np.mgrid[:x_size:n, :y_size:n, :z_size:n]
    return np.stack([xx.ravel(), yy.ravel(), zz.ravel()], axis=1)

print(make_grid(8, 8, 8, 2))

Выход:

[[0. 0. 0.]
 [0. 0. 4.]
 [0. 0. 8.]
 [0. 4. 0.]
 [0. 4. 4.]
 [0. 4. 8.]
 [0. 8. 0.]
 [0. 8. 4.]
 [0. 8. 8.]
 [4. 0. 0.]
 [4. 0. 4.]
 [4. 0. 8.]
 [4. 4. 0.]
 [4. 4. 4.]
 [4. 4. 8.]
 [4. 8. 0.]
 [4. 8. 4.]
 [4. 8. 8.]
 [8. 0. 0.]
 [8. 0. 4.]
 [8. 0. 8.]
 [8. 4. 0.]
 [8. 4. 4.]
 [8. 4. 8.]
 [8. 8. 0.]
 [8. 8. 4.]
 [8. 8. 8.]]

В противном случае с помощью itertools:

from itertools import product

def make_grid(x_size, y_size, z_size, shrink_factor):
    return [(x * x_size, y * y_size, z * z_size)
            for x, y, z in product((i / shrink_factor
                                    for i in range(shrink_factor + 1)), repeat=3)]

print(*make_grid(8, 8, 8, 2), sep='\n')

Выход:

(0.0, 0.0, 0.0)
(0.0, 0.0, 4.0)
(0.0, 0.0, 8.0)
(0.0, 4.0, 0.0)
(0.0, 4.0, 4.0)
(0.0, 4.0, 8.0)
(0.0, 8.0, 0.0)
(0.0, 8.0, 4.0)
(0.0, 8.0, 8.0)
(4.0, 0.0, 0.0)
(4.0, 0.0, 4.0)
(4.0, 0.0, 8.0)
(4.0, 4.0, 0.0)
(4.0, 4.0, 4.0)
(4.0, 4.0, 8.0)
(4.0, 8.0, 0.0)
(4.0, 8.0, 4.0)
(4.0, 8.0, 8.0)
(8.0, 0.0, 0.0)
(8.0, 0.0, 4.0)
(8.0, 0.0, 8.0)
(8.0, 4.0, 0.0)
(8.0, 4.0, 4.0)
(8.0, 4.0, 8.0)
(8.0, 8.0, 0.0)
(8.0, 8.0, 4.0)
(8.0, 8.0, 8.0)
1
jdehesa 4 Июл 2019 в 08:30