I have a class Object, which has a vec3 attribute to store its position
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:
};
Then I have a class Linker, which would "link" Objects, based on their positions.
class Linker
{
Object *obj;
public:
Linker(Object *obj);
virtual void link(Object *o); //this method should perform actions based on Object position
};
In my main.cpp I create few Objects and I'm storing them in a 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
}
}
The nested loop in createPattern() creates a grid of Objects. I would like to link Objects based on their position, and not only allObj[i+1], but I would like to be able to link the Object with vec3 position = <0.0, 1.0, 0.0> like:
And I would like to do the same with every other Object and its neighbours.
My loop creates really few Objects at the moment, but I probably need to create a huge amount of them later.
In this case, is std::vector the best way to store Objects?
Is there a way to store them so I can directly access them by their position?
I was dealing with similar problem in this question. I also wrote an answer on how I solved my problem. So basically I've created my own container consisting of multiple private ones, which you can access by pubic methods. In my case these being overloaded operator() for a direct X/Y access. In your case the base structure holding your data would be compound vector of unique pointers and for direct access you can make overloaded operator()(unsigned x, unsigned y, unsigned z) that would look something like this:
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;
}
This way you can directly give the Linker objects by their X/Y/Z position. Hope this solves your problem.
P.S.: Instead of vector<vector<vector... you could use simple vector<unique_ptr<Object>> but in that case for operator() you would return something like _data[x + y * width + z * height * width] but I'm not quite sure if this it the right formula for object from 3D matrix on pos x/y/z. For 2D matrix it would be _data[x + y * width]
EDIT: Implementation:
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) });
}
While writing this I've realized that I don't really know what exactly your linker does and what is the purpose of linking the i-th object with (i+1)-th object and how it will translate to getting them by X/Y/Z and not a single index.
EDIT2: If you want to link these object like the image shows then the linking process would look something like this:
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
}
This will link every object to its directly neighbouring objects. So for example object at 3/4/5 will be linked to 4/4/5, 3/5/5 and 3/4/6.
EDIT3: Simplified the program structure. Placed all functionality into to Grid class. Here is the code:
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;
};
And this would be the usage of said class doing everything your code samples do:
// 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);
Related
I'm trying to do task in C++. I need create this function:
void fillArray(std::array<std::array<int, maxColumns>, maxRows> array, size_t rows, size_t columns) {
}
Right now my example code looks like this:
#include <iostream>
#include <array>
constexpr int maxColumns = 42;
constexpr int maxRows = 334;
void fillArray(std::array<std::array<int, maxColumns>, maxRows> array, size_t rows, size_t columns) {
}
int main()
{
}
I need to fill the array with numbers from 1 to rows*columns starting from [0][0] and diagonally. How to declare and initialize the function with array in this example and then fill it diagonally? Any help would be greatly appreciated!
It should be
template <std::size_t maxColumns, std::size_t maxRows>
void fillArray(std::array<std::array<int, maxColumns>, maxRows>& array) {
// ...
}
Demo
Let's suppose you use a simple one-dimensional valarray (or array if you insist) of the size width * height wrapped in a class:
class Matrix
{
private:
std::valarray<int> _data;
int _width, _height;
public:
Matrix(int width, int height) : _width(width), _height(height), _data(width * height)
{
}
}
Then you can add a member function that maps x, y coordinates to an item reference:
int& item(int x, int y) { return _data[x + _width * y]; }
... and another one for filling it diagonally like this:
void fillDiagonally(int value = 0, int step = 1)
{
for (int i = 0; i < _height + _width; ++i) {
// calculate starting coordinates (along left edge and then bottom edge)
int row = i < _height ? i : _height - 1;
int col = i < _height ? 0 : i - _height + 1;
// move diagonally up and right until you reach margins, while filling-in values
for (int j = 0; j < _width - col && j <= row; ++j) {
item(col + j, row - j) = value;
value += step;
}
}
}
and use it like this:
int main()
{
Matrix m(8, 5);
m.fillDiagonally(1);
}
This way, you don't need to pass the array as an argument, because it's a part of the class. Otherwise you would have to pass it by reference, like you were suggested above.
I'm currently trying to make a program that will generate a maze to be exported to a game. This program will take user input to set some properties of the maze. I want one of the options to be if the maze will have only two dimensions (a single floor), or three (two or more floors). To achieve that, I'm dynamically allocating an array int the Maze class like so:
In Maze.hpp:
class Maze {
private:
unsigned int width_, length_, height_;
Cell*** matrix = nullptr;
};
In Maze.cpp:
Maze::Maze() { // Default constructor
width_ = 20;
length_ = 20;
height_ = 0;
matrix = new Cell**[width_];
for (unsigned int x {}; x < width_; ++x) {
matrix[x] = new Cell*[length_];
for (unsigned int y {}; y < length_; ++y) {
matrix[x][y] = new Cell(x, y);
}
}
}
Maze::Maze(int width, int length) { // 2D maze constructor
width_ = width;
length_ = length;
height_ = 0;
matrix = new Cell**[width_];
for (unsigned int x {}; x < width_; ++x) {
matrix[x] = new Cell*[length_];
for (unsigned int y {}; y < length_; ++y) {
matrix[x][y] = new Cell(x, y);
}
}
}
Maze::Maze(int width, int length, int height) { // 3D maze constructor
width_ = width;
length_ = length;
height_ = height;
matrix = new Cell**[width_];
for (unsigned int x {}; x < width_; ++x) {
matrix[x] = new Cell*[length_];
for (unsigned int y {}; y < length_; ++y) {
matrix[x][y] = new Cell[height];
for (unsigned int z {}; z < height_; ++z) {
matrix[x][y][z] = Cell(x, y, z);
}
}
}
}
But as you can see, if I use two dimensions, I end up with a pointer for every individual cell in the maze, meanwhile, with three dimensions I end up with a cell object. I would prefer if in both cases I could have a cell object, but I don't know how to achieve that.
Is there a way to do this? Or is this the only option I have?
As asked, here is the declaration of Cell:
Cell.hpp:
class Cell {
private:
unsigned int xPos_, yPos_, zPos_;
public:
Cell(unsigned int xPos, unsigned int yPos);
Cell(unsigned int xPos, unsigned int yPos, unsigned int zPos);
Cell();
};
Cell.cpp:
Cell::Cell(unsigned int xPos, unsigned int yPos) {
xPos_ = xPos;
yPos_ = yPos;
}
Cell::Cell(unsigned int xPos, unsigned int yPos, unsigned int zPos) {
xPos_ = xPos;
yPos_ = yPos;
zPos_ = zPos;
}
As suggested in the comments of the question, I'll change to std::vector instead of using triple pointers.
Also, as a 2D array is simply a 3D array with only one value in the third dimension, I will just change the code to that. (This was also suggested in the comments)
I'll update this answer with the new code when I'm done with it.
UPDATE:
Here's what the final code looks like:
Cell.hpp:
class Cell {
private:
unsigned xPos_, yPos_, zPos_;
public:
Cell(unsigned xPos, unsigned yPos, unsigned zPos);
Cell();
};
Cell.cpp:
Cell::Cell(unsigned xPos, unsigned yPos, unsigned zPos) {
xPos_ = xPos;
yPos_ = yPos;
zPos_ = zPos;
}
Maze.hpp:
class Maze {
private:
unsigned width_, length_, height_;
std::vector<std::vector<std::vector<Cell>>> matrix;
void generateMatrix();
public:
Maze();
Maze(unsigned width, unsigned length);
Maze(unsigned width, unsigned length, unsigned height);
};
Maze.cpp:
Maze::Maze() { // Default constructor
width_ = 20;
length_ = 20;
height_ = 1;
Maze::generateMatrix();
}
Maze::Maze(unsigned width, unsigned length) { // 2D maze constructor
width_ = width;
length_ = length;
height_ = 1;
Maze::generateMatrix();
}
Maze::Maze(unsigned width, unsigned length, unsigned height) { // 3D maze constructor
width_ = width;
length_ = length;
height_ = height;
Maze::generateMatrix();
}
void Maze::generateMatrix() {
for (unsigned x {}; x < width_; ++x) {
matrix.push_back(std::vector<std::vector<Cell>>());
for (unsigned y {}; y < length_; ++y) {
matrix.at(x).push_back(std::vector<Cell>());
for (unsigned z {}; z < height_; ++z) {
matrix.at(x).at(y).push_back(Cell(x,y,z));
}
}
}
}
I'm trying to code a function that, given an index as the input argument, extract the corresponding layer from a 3D matrix, returning a 2D matrix.
My default 3D matrix constructor looks something like this:
Matrice3D(unsigned int depth, unsigned int height, unsigned int width, const T &value) : _3D_matrix(0), _height(0), _width(0), _depth(0) {
try {
_3D_matrix = new T[height * width * depth];
for (int z = 0; z < depth; z++) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
_3D_matrix[y * width * depth + x * depth + z] = value;
}
}
}
}
catch(...) {
delete[] _3D_matrix;
throw;
}
_height = height;
_width = width;
_depth = depth;
}
(the try/catch is still a wip, I know it's not a thing to do).
So far, I've coded this:
void slice(int index) {
try{
_2D_matrix = new T[_height * _width];
}catch(...){
delete[] _2D_matrix;
_height = 0;
_width = 0;
_depth = 0;
throw;
}
_depth = 1;
for (int k = 0; k< _depth; k++) {
for (int j = 0; j< _height; j++) {
for (int i = 0; i< _width; i++) {
_2D_matrix[j * _width + i] =
_3D_matrix[j * _width * _depth + i * _depth + index];
}
}
}
}
I guess the logic behind the assignment done with the nested for cycles is right, but I don't really know how to return the new matrix.
From the main, used to test the code, I'm calling
std::cout << "--------TEST SLICE------------" << std::endl;
Matrice3D<int> m1(3,3,3,17);
std::cout << "Setter su (0,0,2,99)" << std::endl;
m1(0,0,2,91); //setting a value
m1.slice(2);
std::cout << "Matrix obtained from slicing the layer 2: " <<std::endl;
std::cout << m1;
but I keep getting the first layer of the matrix, whatever index I choose for the input.
Create a new class Matrice2D and return that in slice().
The reason why your get total garbage in your code is that you destroy the _depth of the 3D matrix. It's not even the first layer but really just garbage.
The only time new and delete should appear is in classes named something_ptr. You don't need raw pointers here, and you should be returning a 2DMatrix from slice.
template <typename T>
class 2DMatrix;
template <typename T>
class 3DMatrix {
std::vector<T> data;
std::size_t height, width, depth;
public:
3DMatrix(std::size_t height, std::size_t width, std::size_t depth, T value = {})
: data(height * width * depth, value),
height(height),
width(width),
depth(depth)
{}
2DMatrix<T> slice(std::size_t index) {
2DMatrix<T> result(height, width);
for (std::size_t i = index; i < data.size(); i += depth) {
result.data[i / depth] = data[i];
}
return result;
}
// other members
}
template <typename T>
class 2DMatrix {
std::vector<T> data;
std::size_t height, width;
friend class 3DMatrix<T>;
public:
2DMatrix(std::size_t height, std::size_t width, T value = {})
: data(height * width, value),
height(height),
width(width)
{}
// other members
}
I am doing the "Game of life" as an assignment for the college, the tutor has given to us part of the code, but I am having problem for understand two parts.
First:
grid(int scale) : scale_(scale), width_(problem_definition::width(scale)), height_(problem_definition::height(scale)), data_(new problem_definition::data_type[width_*height_])
Until I can understand is the moment that he requests for the memory which is used for the grid for the simulation. However, I can not grasp the syntax beyond the new. why are those brackets with an empty space? what does mean the colon after grid (int scale)?
Second:
void initialize()
{
for (std::size_t y = 0; y < height_; ++y)
{
for (std::size_t x = 0; x < width_; ++x)
{
at(x,y) = problem_definition::initialize(x, y, scale_);
}
}
}
what is this "at()" inside the second for loop?
I would appreciate any insight here is the full struct definition:
struct grid
{
grid(int scale) : scale_(scale), width_(problem_definition::width(scale)), height_(problem_definition::height(scale)), data_(new problem_definition::data_type[width_*height_])
{
}
void initialize()
{
for (std::size_t y = 0; y < height_; ++y)
{
for (std::size_t x = 0; x < width_; ++x)
{
at(x,y) = problem_definition::initialize(x, y, scale_);
}
}
}
problem_definition::data_type at(std::size_t x, std::size_t y, int dx, int dy)
{
if (dx<0 && -dx>x) return problem_definition::out_of_bounds_value();
if (dy<0 && -dy>y) return problem_definition::out_of_bounds_value();
if (x + dx >= width_) return problem_definition::out_of_bounds_value();
if (y + dy >= height_) return problem_definition::out_of_bounds_value();
return at((int)x + dx, (int)y + dy);
}
problem_definition::data_type& at(std::size_t x, std::size_t y)
{
return data_[x + y*width_];
}
void swap(grid& other)
{
std::swap(scale_, other.scale_);
std::swap(width_, other.width_);
std::swap(height_, other.height_);
std::swap(data_, other.data_);
}
void print(std::ostream& str)
{
for (std::size_t y = 0; y < height_; ++y)
{
for (std::size_t x = 0; x < width_; ++x)
{
str << at(x, y);
}
str << std::endl;
}
}
private:
int scale_;
std::size_t width_;
std::size_t height_;
std::unique_ptr<problem_definition::data_type[]> data_;
};
Let's add some white space to the first line to make it easier to read:
grid(int scale) : scale_(scale),
width_(problem_definition::width(scale)),
height_(problem_definition::height(scale)),
data_(new problem_definition::data_type[width_*height_])
Now we can easily see the colon (a : is a colon, a ; is a semicolon) defines an initialiser list which takes a series of var(value) pairs and assigns each value to each var.
I don't see any "brackets with an empty space" so can't answer that. But beyond new is just a standard array type of the form: element_type[length]. The element type is problem_definition::data_type and the array is of length width_ times height_.
Finally, at() is just a function call that returns a reference. If you study the function definition:
problem_definition::data_type& at(std::size_t x, std::size_t y)
{
return data_[x + y*width_];
}
then you can see the line with the call to at(), via the magic of references, is the same as the following:
data_[x + y*width_] = problem_definition::initialize(x, y, scale_);
I have declared a class Image with two operator() functions, one for read-only, the other for read-and-write access.
Here an extract:
class Image {
//...
public:
uint16_t operator()(int x, int y) const
{
return data_[x + y*width_]; // read-only at pixle (x,y)
}
uint16_t & operator()(int x, int y)
{
return data_[x + y*width_]; // read/write to pixle (x,y)
}
//...
}
After this, I declared an object of Image in the main() function and wrote to it (which has to work because of the mentioned public Interface operator()), but several compilers only keep recognizing the first operator() function which has only permission to read.
Example of this:
if (count_alive_neighbors(image, i, j) == 3) {
image(i, j) = 255;
}
My thought was that maybe one could overcome this problem by declaring a pointer and by this changing the value. Code for this:
uint16_t* f = &image(i, j);
*f = 255;
On Microsoft Visual Studio 2015 this first worked tested alone outside the if-loop, but inside the just mentioned function it didn't. But it's not a compiler error, I've tested it with Clang, g++ and MinGW.
All are printing out an error message like this:
error: lvalue required as unary '&' operand
uint16_t* f = &(image(i, j));
^
To sum it up, the question is the following: how could one overcome this problem by not focusing on that pointer declarations, what can one do to tell the compiler which version of operator() it has to use? It doesn't recognize it on its own or maybe I'm not recognizing which settings/code one has to change to make the program work.
Thanks in advance.
edit: whole class definition and function
#include <vector>
#include <string>
#include <stdexcept>
#include <fstream>
#include <cstdint>
class Image
{
int width_;
int height_;
std::vector<uint16_t> data_;
public:
Image()
: width_(0)
, height_(0)
{}
Image(unsigned int width, unsigned int height)
: width_(width)
, height_(height)
, data_(width*height, uint16_t())
{}
int width() const
{
return width_;
}
int height() const
{
return height_;
}
int size() const
{
return width_*height_;
}
void resize(unsigned int new_width, unsigned int new_height)
{
data_.resize(new_width*new_height, uint16_t());
width_ = new_width;
height_ = new_height;
}
uint16_t operator()(int x, int y) const
{
return data_[x + y*width_];
}
uint16_t & operator()(int x, int y)
{
return data_[x + y*width_];
}
uint16_t get_periodic(int x, int y) const
{
int xres = x % width_;
int yres = y % height_;
return data_[xres + yres*width_];
}
};
int count_alive_neighbors(Image const & image, int x, int y) {
int res = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (image.get_periodic(x + i, y + j) == 255) {
res += 1;
}
}
}
if (image.get_periodic(x, y) == 255) {
res -= 1;
}
}
Image conway_step(Image const & image) {
for (int i = 0; i <= image.width(); i++) {
for (int j = 0; j <= image.height(); j++) {
if (count_alive_neighbors(image, i, j) == 2)
{
}
if (count_alive_neighbors(image, i, j) == 3) {
image(i, j) = 255;
}
if (count_alive_neighbors(image, i, j) < 2) {
image(i, j) = 0;
}
if (count_alive_neighbors(image, i, j) > 3) {
image(i, j) = 255;
}
}
}
}
int main() {
Image img(3, 3); // declaring object
img(3, 3) = 255; /* !ATTENTION! this works, but inside
conway_steps it doesn't */
}
[Based on the comments] conway_step is supposed to make a copy of its argument, modify that copy, and return the copy. Your problem is that you don't make the copy and try to modify the original.
Please change your function signature from
Image conway_step(Image const & image)
to
Image conway_step(Image & const image) //ill formed
or in a better way
Image conway_step(Image & image)
In first case, it is equivalent to const Image & image, so it calls the const qualified operator => image(i, j)=255; => uint16_t=255 => left operand must be l-value error
In second/third case, you declare a const reference to a non const object.