我有一个班级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]
,但我希望能够link
Object
与vec3 position = <0.0, 1.0, 0.0>
一样:
我想对其他Object
及其邻居做同样的事情。
我的循环现在创建了很少的Objects
,但我可能需要稍后创建大量的。{/ p>
在这种情况下,std::vector
是存储Objects
的最佳方式吗?
有没有办法存储它们,以便我可以通过它们的位置直接访问它们?
答案 0 :(得分:2)
我在this question处理类似的问题。我还写了一个关于我如何解决问题的答案。所以基本上我已经创建了自己的容器,由多个私有容器组成,您可以通过公共方法访问它。在我的情况下,这些是重载operator()直接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位置直接给出Linker对象。希望这能解决你的问题。
PS:而不是vector<vector<vector...
你可以使用简单的vector<unique_ptr<Object>>
,但在这种情况下,对于operator(),你会返回类似_data[x + y * width + z * height * width]
的内容,但我不太确定它是pos x / y / z上3D矩阵的对象的正确公式。对于2D矩阵,它将是_data[x + y * width]
编辑:实施:
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);