存储和访问对象位置向量
Storing and accessing Object position vector
我有一个 class 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:
};
然后我有一个 class Linker
,根据他们的位置 "link" 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
的网格。我想 link Objects
基于他们的位置,而不仅仅是 allObj[i+1]
,但我希望能够 link
Object
和 vec3 position = <0.0, 1.0, 0.0>
喜欢:
我想对所有其他 Object
及其邻居也这样做。
我的循环目前创建的很少 Objects
,但我以后可能需要创建大量它们。
在这种情况下,std::vector
是存储 Objects
的最佳方式吗?
有没有办法存储它们以便我可以通过它们的位置直接访问它们?
我在 中处理过类似的问题。我还写了一个关于我如何解决问题的答案。所以基本上我已经创建了我自己的容器,其中包含多个私有容器,您可以通过公共方法访问这些容器。在我的例子中,这些被重载 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 位置给出链接器对象。希望这能解决您的问题。
P.S.: 你可以使用简单的 vector<unique_ptr<Object>>
而不是 vector<vector<vector...
但在那种情况下,对于 operator() 你会 return 像 _data[x + y * width + z * height * width]
但我不太确定这是否是 pos x/y/z 上 3D 矩阵对象的正确公式。对于二维矩阵,它将是 _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) });
}
在写这篇文章的时候我意识到我真的不知道你的 linker 到底是做什么的以及 link 使用 (i+) 第 i 个对象的目的是什么1)-th 对象以及它将如何转换为通过 X/Y/Z 而不是单个索引获取它们。
EDIT2:如果您想要 link 这些对象,如图所示,那么 linking 过程将如下所示:
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
}
这将 link 每个对象与其直接相邻的对象。因此,例如 3/4/5 处的对象将 linked 为 4/4/5、3/5/5 和 3/4/6。
EDIT3:简化了程序结构。将所有功能放入网格 class。这是代码:
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;
};
这就是所说 class 执行您的代码示例所做的一切的用法:
// 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);
我有一个 class 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:
};
然后我有一个 class Linker
,根据他们的位置 "link" 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
的网格。我想 link Objects
基于他们的位置,而不仅仅是 allObj[i+1]
,但我希望能够 link
Object
和 vec3 position = <0.0, 1.0, 0.0>
喜欢:
我想对所有其他 Object
及其邻居也这样做。
我的循环目前创建的很少 Objects
,但我以后可能需要创建大量它们。
在这种情况下,std::vector
是存储 Objects
的最佳方式吗?
有没有办法存储它们以便我可以通过它们的位置直接访问它们?
我在 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 位置给出链接器对象。希望这能解决您的问题。
P.S.: 你可以使用简单的 vector<unique_ptr<Object>>
而不是 vector<vector<vector...
但在那种情况下,对于 operator() 你会 return 像 _data[x + y * width + z * height * width]
但我不太确定这是否是 pos x/y/z 上 3D 矩阵对象的正确公式。对于二维矩阵,它将是 _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) });
}
在写这篇文章的时候我意识到我真的不知道你的 linker 到底是做什么的以及 link 使用 (i+) 第 i 个对象的目的是什么1)-th 对象以及它将如何转换为通过 X/Y/Z 而不是单个索引获取它们。
EDIT2:如果您想要 link 这些对象,如图所示,那么 linking 过程将如下所示:
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
}
这将 link 每个对象与其直接相邻的对象。因此,例如 3/4/5 处的对象将 linked 为 4/4/5、3/5/5 和 3/4/6。
EDIT3:简化了程序结构。将所有功能放入网格 class。这是代码:
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;
};
这就是所说 class 执行您的代码示例所做的一切的用法:
// 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);