2016-12-10 4 views
3

У меня есть класс Object, который имеет атрибут vec3 хранить свою позициюХранение и доступ к объектной позиции вектора

class Object{ 
public: 
    Object(); 
    ~Object(); 
    glm::vec3 position; 
    virtual float getX(); //these methods get the x, y and z value of the vec3 position 
    virtual float getY(); 
    virtual float getZ(); 

private: 
}; 

Тогда у меня есть класс Linker, который бы «ссылка» Objects, основываясь на своих позициях.

class Linker 
{ 
    Object *obj; 
public: 
    Linker(Object *obj); 
    virtual void link(Object *o); //this method should perform actions based on Object position 
}; 

В моей main.cpp я создаю несколько Objects, и я храню их в std::vector

static vector<unique_ptr<Object>> allObj; 
static vector<Linker> allLinkers; 

unique_ptr<Object> createNewObj(int x, int y, int z) { 
    unique_ptr<Object> obj(new Object()); 
    obj->position(vec3(x, y, z)); 
    return obj; 
    } 

void createPattern() 
{ 
    for (int x = 0; x < 3; x++) 
    { 
     for (int z = 0; z < 3; z++) 
     { 
      allObj.push_back(createNewObj(x, 1.0f, z)); 
     } 
    } 

    for (auto &p : allObj) { 
     Linker lnkr = Linker(p); 
     //EDIT 
     allLinkers.push_back(lnkr); 
    } 
} 

void linkPattern() 
{ 
    for (int i = 0; i < allObj.size() - 1; i++) 
    { 
     auto p = allObj[i+1]; //this is where my problem comes up 
     allLinkers[i].link(p); //takes the linker of the first object and "links" it with the second 
    } 
} 

Вложенный цикл в createPattern() создает сетку Objects. Я хотел бы связать Objects на основе их позиции, а не только allObj[i+1], но я хотел бы быть в состоянии linkObject с vec3 position = <0.0, 1.0, 0.0> как:

Grid of Objects

И я хотел бы сделать то же самое с каждым другие Object и его соседи.

В настоящее время моя петля создает очень мало Objects, но мне, вероятно, придется создать огромное количество их позже.

В этом случае std::vector лучший способ хранения Objects? Есть ли способ их хранения, чтобы я мог напрямую обращаться к ним по их положению?

+0

Из того, что я понимаю, что вы хотите эффективный способ, чтобы найти объект на определенный должность? –

+0

Точно. Я хотел бы иметь возможность сказать: link obj к объекту x + 1, z + 1 и т. Д. – Koosshh56

+0

Самый простой способ, который до сих пор очень эффективен, - это std :: map. Используйте позицию как ключ и объект как значение. Однако, если у вас нет разреженной сетки (каждая позиция содержит объект), вы можете просто использовать многомерный массив. –

ответ

2

Я имел дело с аналогичной проблемой в this question. Я также написал ответ о том, как я решил свою проблему. Поэтому в основном я создал свой собственный контейнер, состоящий из нескольких частных, к которым вы можете обращаться по лобовым методам. В моем случае это перегруженный оператор() для прямого доступа X/Y. В вашем случае базовая структура проведение данных будет соединение вектор уникальных указателей и для прямого доступа вы можете сделать перегружен operator()(unsigned x, unsigned y, unsigned z), что будет выглядеть примерно так:

class Grid { 
public: 
    Object& operator()(unsigned x, unsigned y, unsigned z) noexcept { 
     return *_data[z][y][x]; 
    } 

    // same method returning const reference(read-only) 
    const Object& operator()(unsigned x, unsigned y, unsigned z) const noexcept { 
     return *_data[z][y][x]; 
    } 

    /* Safer but throws std::out_of_range exception, which you should handle 
    Object& operator()(unsigned x, unsigned y, unsigned z) { 
     return *_data.at(z).at(y).at(z); 
    } 
    */ 
private: 
    vector<vector<vector<unique_ptr<Object> > > > _data; 
} 

Таким образом, вы можете непосредственно получить объекты компоновщика по их Положение X/Y/Z. Надеюсь, это решает вашу проблему.

PS: Вместо vector<vector<vector... вы можете использовать простой vector<unique_ptr<Object>>, но в этом случае для оператора() вы бы вернуть что-то вроде _data[x + y * width + z * height * width], но я не совсем уверен, если это оно правильная формула для объекта из 3D матрицы на пос х/г/г. Для 2D-матрицы было бы _data[x + y * width]

EDIT: Реализация:

class Grid { 
public: 
    // Constructor fills the Grid with Objects created from theirs default constructor 
    Grid(unsigned width, unsigned height, unsigned depth) 
     : _width(width), _height(height), _depth(depth) { 
     _data.resize(depth); 
     for (unsigned i = 0; i < depth; ++i) { 
     _data[i].resize(height); 
     for (unsigned j = 0; i < height; ++i) 
      _data[i][j].push_back(make_unique<Object>()); 
      // Calls a consturctor of Object 
      // If you don't plan on filling every single position you can instead fill it with nullptr to save memory 
     } 
    } 

    Object& operator()(unsigned x, unsigned y, unsigned z) { 
     return *_data[z][y][x]; 
    } 

    unsigned size() { return _width * _height * _depth; }  
    unsigned width() { return _width; }  
    unsigned height() { return _height; }  
    unsigned depth() { return _depth; } 

private: 
    vector<vector<vector<unique_ptr<Object> > > > _data; 
    unsigned _width; 
    unsigned _height; 
    unsigned _depth; 
} 

static Grid allObj(width, height, depth); 
static vector<Linker> allLinkers; 

unique_ptr<Object> createNewObj(int x, int y, int z) { 
    unique_ptr<Object> obj(new Object()); 
    obj->position(vec3(x, y, z)); 
    return obj; 
    } 

void createPattern() 
{ 
    // no need for inserting because Objects are created on allObj creation 

    // changed the iterator based range for to normal for loops 
    for (unsigned k = 0; k < allObj.depth - 1; ++k) 
     for (unsigned j = 0; j < allObj.height - 1; ++j) 
      for (unsigned i = 0; i < allObj.width - 1; ++i) 
      Linker.push_back({ allObj(i, j, k) }); 
} 

Во время написания этого я понял, что я не знаю, что именно ваш компоновщик делает и то, что является целью увязки I -го объекта с (i + 1) -го объекта и как он будет переводить на получение их по X/Y/Z, а не по одному индексу.

EDIT2: Если вы хотите, чтобы связать эти объекты, как изображение показывает то процесс связывания будет выглядеть примерно так:

for (unsigned k = 0; k < allObj.depth - 1; ++k) 
    for (unsigned j = 0; j < allObj.height - 1; ++j) 
     for (unsigned i = 0; i < allObj.width - 1; ++i) { 
     auto p = allObj(i + 1, j, k); 
     allLinkers[i].link(p); 
     p = allObj(i, j + 1, k); 
     allLinkers[i].link(p); 
     p = allObj(i, j, k + 1); 
     allLinkers[i].link(p); 
     // and continue with whatever else you want to link 
     // as you can see this is quite unefective so maybe modifying link method 
     // so it takes no parameters and automatically links all neighbouring objects would be better 
     } 

Это будет связывать каждый объект с его непосредственно соседними объектами.Так, например, объект на 3/4/5 будет связан с 4/4/5, 3/5/5 и 3/4/6.

EDIT3: Упрощенная структура программы. Поместил всю функциональность в класс Grid. Вот код:

class Grid { 
public: 
    // Create a grid with set width, height and depth 
    Grid(unsigned width, unsigned height, unsigned depth) 
      : _width(width), _height(height), _depth(depth) { 

     // This replaces the createPattern function 
     // Creates both objects and linkers 
     for (unsigned i = 0; i < size(); ++i) { 
      _objects.push_back(make_unique<Object>()); 
      _linkers.push_back({ _objects[i].get() }); 
     } 

     // This replaces the linkPattern function 
     // Does the linking exactly as shown on the picture 
     for (unsigned i = 0; i < size(); ++i) { 
      _linkers[i].link(&object(_objects[i]->getX(), _objects[i]->getY(), _objects[i]->getZ() + 1)); 
      _linkers[i].link(&object(_objects[i]->() + 1, _objects[i]->getY(), _objects[i]->getZ())); 
      _linkers[i].link(&object(_objects[i]->getX() + 1, _objects[i]->getY(), _objects[i]->getZ() + 1)); 
     } 
    } 

    // Direct access operator 
    Object& object(unsigned x, unsigned y, unsigned z) noexcept { 
     return *_objects[x + y * _width + z * _height * _width]; 
    } 

    // another possible implementation of Direct access operator 
    // checks if element you want is 'in range' 
    // NOTE: may throw std::out_of_range 
    const Object& operator()(unsigned x, unsigned y, unsigned z) const { 
     size_t position = x + y * _width + z * _height * _width; 
     if (position >= _objects.size() || x > _width || y > _height || z > _depth) 
      throw std::out_of_range("index is out of range"); 
     return *_objects[x + y * _width + z * _height * _width]; 
    } 

    // Direct access for linkers 
    Linker& linker(unsigned x, unsigned y, unsigned z) noexcept { 
     return _linkers[x + y * _width + z * _height * _width]; 
    } 

    // Getters 
    constexpr unsigned size() const noexcept { return _width * _height * _depth; } 
    constexpr unsigned width() const noexcept { return _width; } 
    constexpr unsigned height() const noexcept { return _height; } 
    constexpr unsigned depth() const noexcept { return _depth; } 

    // Iterators - using ranged for would loop throught all the Objects from _objects 

    using iterator = std::vector<unique_ptr<Object> >::iterator; 
    using const_iterator = std::vector<unique_ptr<Object> >::const_iterator; 
    using reverse_iterator = std::vector<unique_ptr<Object> >::reverse_iterator; 
    using const_reverse_iterator = std::vector<unique_ptr<Object> >::const_reverse_iterator; 

    iterator begin() noexcept { return _objects.begin(); } 
    const_iterator begin() const noexcept { return _objects.begin(); } 

    iterator end() noexcept { return _objects.end(); } 
    const_iterator end() const noexcept { return _objects.end(); } 

    reverse_iterator rbegin() noexcept { return _objects.rbegin(); } 
    const_reverse_iterator rbegin() const noexcept { return _objects.rbegin(); } 

    reverse_iterator rend() noexcept { return _objects.rend(); } 
    const_reverse_iterator rend() const noexcept { return _objects.rend(); } 

private: 
    vector<Linker> _linkers; 
    vector<unique_ptr<Object> > _objects; 
    const unsigned _width; 
    const unsigned _height; 
    const unsigned _depth; 
}; 

И это будет использование указанного класса делает все ваши образцы кода сделать:

// The grid containing all the objects and linkers 
Grid allObj(3, 1, 3); 

// You can access objects like this 
allObj.object(x, y, z); 

// or like this (returns const& (read-only)) 
allObj(x, y, z); 

// Likewise the linker 
allObj.linker(x, y, z); 
+0

, а также вы можете использовать в() для векторов вместо оператора []. at() проверяет, находится ли вы в пределах диапазона вектора, тем самым безопаснее. –

+0

Линкер выполняет физический расчет на объекте. Вторая часть вашего «вопроса», о том, как она будет переводиться, чтобы получить их по X, Y, Z, это на самом деле моя проблема. – Koosshh56

+0

Как я могу завершить метод insert()? – Koosshh56

Смежные вопросы