C++ 2D Vector setting a position within the vector - c++

I have an assignment to make a robot controller for a University project. At the moment it is going quite well, but I have a niggling bug that is just darn annoying and I can't seem to correct it.
Basically, I have to design a contrasting controller to enable random movement while avoiding obstacles. So, I have a robot which appears as "R" on the console, which is within a 10 by 10 area. Here is the code I use to initialise my 2D vector, and then draw the grid:
void matrix::init() // init my 2D vector
{
dot = 10; // 10 by 10 area
vector2D.resize(dot);
for (int i=0; i<dot; i++)
{
vector2D[i].resize(dot);
}
}
void matrix::draw() // drawing the vector to the screen
{
for(int i=0; i<dot; i++)
{
for(int j=0; j<dot; j++)
{
cout <<vector2D[i][j]<<"."; // I being the Y access, J the X access
}
cout<<endl;
}
}
void matrix::update()
{
init();
draw();
}
This is in its own class called matrix.cpp, which is then called in the main.cpp with m.update(); m being an object of matrix
Now, the robot position on screen is being set with this code within the matrix.cpp class
void matrix::robotPosition(int x, int y)
{
bot = 'R';
cout << "X Pos"<< x <<endl;
cout << "Y Pos"<< y <<endl;
vector2D[x][y] = bot; // Outputting location of robot onto the grid / matrix
}
There is more code I have developed to control the position on screen, but I don't think that is needed at this point in my question.
int main()
{
matrix m;
robot r;
while(true)
{
m.update(); // vector2D init and draw
m.robotPosition(r.getX(), r.getY());
r.update();
system("pause");
}
}
Every time my program loops through the while loop it draws another robot on the screen, but doesn't seem to remove the old one. The code works by assigning a certain X and Y in the 2D vector with the char 'R' (Which is my Robot). Is my thinking correct that I will have to draw the 2D matrix after each movement cycle?
Thanks

When you first set the robot position to, say, (5,5), you will set vector2D[5][5] to R. Then if you set the position to something like (5,6), you will set vector2D[5][6] to R. Now both elements [5][5] and [5][6] are set to R, so the robot is in both positions.
There are a few solutions that depend on how you want to design it:
You can store the current robot position in matrix and at the beginning of robotPosition set that position to whatever the non-robot character is. This will clear the previous position before setting the new one.
You can clear the entire matrix at the beginning of each frame. You are calling update at the beginning of each frame, which attempts to resize the vectors to exactly the same size they already are - this doesn't clear it. Instead, you should do that work in the constructor, and you can turn init into a clear function.
If you want to use a different matrix for each time step, then you need to move the declaration of matrix m; into the while loop. Then you have one for each frame which should be cleared during construction (if you move the init stuff to the constructor).

Related

Data analysis - memory bug c++

I am a data scientist, currently working on some C++ code to extract triplet particles from a rather large text file containing 2D coordinate data of particles in ~10⁵ consecutive frames. I am struggling with a strange memory error that I don't seem to understand.
I have a vector of structs, which can be divided into snippets defined by their frame. For each frame, I build an array with unique ID's for each individual coordinate pair, and if at any point the coordinate pair is repeated, the coordinate pair is given the old coordinate pair. This I then use later to define whether the particle triplet is indeed a trimer.
I loop over all particles and search forward for any corresponding coordinate pair. After I'm done, and no particles were found, I define this triplet to be unique and push the coordinates into a vector that corresponds to particle IDs.
The problem is: after the 18th iteration, at line trimerIDs[i][0] = particleCounter; , the variable trimerCands (my big vector array) suddenly becomes unreadable. Can this be that the vector pointer object is being overwritten? I put this vector fully on the heap, but even if I put it on stack, the error persists.
Do any of you have an idea of what I might be overlooking? Please note that I am rather new at C++, coming from other, less close to the metal, languages. While I think I understand how stack/heap allocations work, especially with respect to vectors/vector structs, I might be very wrong!
The error that Eclipse gives me in the variables tab is:
Failed to execute MI command:
-data-evaluate-expression trimerCands
Error message from debugger back end:
Cannot access memory at address 0x7fff0000000a
The function is as follows.
struct trimerCoords{
float x1,y1,x2,y2,x3,y3;
int frame;
int tLength1, tLength2, tLength3;
};
void removeNonTrimers(std::vector<trimerCoords> trimerCands, int *trCandLUT){
// trimerCands is a vector containing possible trimers, tLengthx is an attribute of the particle;
// trCandLUT is a look up table array with indices;
for (int currentFrame = 1; currentFrame <=framesTBA; currentFrame++){ // for each individual frame
int nTrimers = trCandLUT[currentFrame] - trCandLUT[currentFrame-1]; // get the number of trimers for this specific frame
int trimerIDs[nTrimers][3] = {0}; // preallocate an array for each of the inidivual particle in each triplet;
int firstTrim = trCandLUT[currentFrame-1]; // first index for this particular frame
int lastTrim = trCandLUT[currentFrame] - 1; // last index for this particular frame
bool found;
std::vector<int> traceLengths;
traceLengths.reserve(nTrimers*3);
// Block of code to create a unique ID array for this particular frame
std::vector<Particle> currentFound;
Particle tempEntry;
int particleCounter = 0;
for (int i = firstTrim; i <= lastTrim; i++){
// first triplet particle. In the real code, this is repeated three times, for x2/y2 and x3/y3, corresponding to the
tempEntry.x = trimerCands[i].x1;
tempEntry.y = trimerCands[i].y1;
found = false;
for (long unsigned int j = 0; j < currentFound.size(); j++){
if (fabs(tempEntry.x - currentFound[j].x) + fabs(tempEntry.y - currentFound[j].y) < 0.001){
trimerIDs[i][0] = j; found = true; break;
}
}
if (found == false) {
currentFound.push_back(tempEntry);
traceLengths.push_back(trimerCands[i].tLength1);
trimerIDs[i][0] = particleCounter;
particleCounter++;
}
}
// end block of create unique ID code block
compareTrips(nTrimers, trimerIDs, traceLengths, trimerfile_out);
}
}
If anything's unclear, let me know!

QT collision detection between 2 QGraphicsPixmapItems

Link to project
The interesting parts should be in gameengine.cpp's "launchSplash" -function and splashanimation.cpp
The game creates the bubbles randomly in the acceptable are. The player's job is to shoot the bubbles with water drops. The water drops are launched from the middle bottom part of the game screen. The grids are only used for debugging, and will later on be gone, but it makes visualizing the areas easier.
The bubbles are destroyed by shooting the water drop at them, but the water drop disappears when it hits a bubble or the upper boundary of the game. The water drop shoots to the direction of a mouse click.
I'm trying to create a collision detection for a basic bubble shooter game, but I'm not sure how I can detect the collision in a neat way.
The game board looks something like this game board, the water drops are shot from the middle bottom part of the screen to the direction of the cursor.
Eventually I'll have the water drop ricochet from the walls, but at the moment I'm contempt with figuring out how to detect collisions in the first place.
The game board is 500x600 units (width x height), so the point the water drop is shot at is (250, 600).
When the water drop is shot, I use
void GameEngine::launchSplash(int clickX, int clickY){
// <my long method of calculating the coordinates for the water drop's path>
graphicalGameBoard_.animateSplash(graphicalGameBoard_.width()/2, graphicalGameBoard_.height(), xDestination, yDestination);
}
where xDestination and yDestionation are the place the water drop will end up if it travels unhindered. The water drop will either end up at x=0 / x=500 and/or y=0/y=600, but I don't think that's relevant.
The bubbles are added to the game board with
board_.clear();
for(int y = 0; y < HEIGHT; ++y)
{
std::vector< std::shared_ptr<Bubble> > row;
for(int x = 0; x < WIDTH; ++x)
{
std::shared_ptr<Bubble> newBubble = nullptr;
// There will be bubbles only in the top 3/4 of the board only in the middle
// (i.e. not in the first two and last two columns).
if (y < HEIGHT*3/4 && x > 1 && x < WIDTH-2)
{
// Generate random numbers using the enumearation type defined in
// file bubble.hh. The value COLOR_COUNT is used to represent no bubble.
std::uniform_int_distribution<int> distribution(RED,COLOR_COUNT);
// If you want no empty squares, change the initialization to:
// std::uniform_int_distribution<int> distribution(RED,BLUE);
Color color = static_cast<Color>(distribution(randomEngine_));
if(color != COLOR_COUNT) {
newBubble = std::make_shared<Bubble>(x, y, color);
}
}
row.push_back(newBubble);
}
board_.push_back(row);
}
in the gameengine.cpp which draws the board and the water drop being shot at the bubbles.
The water drops are drawn using
SplashAnimation::SplashAnimation(GameBoard* scene, QPointF startPoint, QPointF endPoint):
QVariantAnimation(0),
scene_(scene),
item_()
{
scene_->addItem(&item_);
// The animation runs for the given duration and moves the splash
// smoothly from startpoint to endpoint.
setDuration(2000);
setKeyValueAt(0, QPointF(startPoint));
setKeyValueAt(1, QPointF(endPoint));
}
I figured there are two ways to do this: either the inbuilt QT Collision detection or doing a separate calculation. I was not able to work with QT Collision and my attempts at detecting the collision manually did not really work out too well.
I already have a function for detecting bubble objects at certain cells, but it's in column/row instead of raw coordinates (500x600).
std::shared_ptr<Bubble> GameEngine::bubbleAt(int x, int y) const
{
if (0 <= x and x < WIDTH and 0 <= y and y < HEIGHT){
return board_.at(y).at(x);
}
else{
return nullptr;
}
}
Edit: Currently I'm trying to work on something like this, but I'm afraid it's going to be a bit heavy for the game since it iterates so much (or not?):
for (int i = 0; i<600;++i)
{
xfract = (xDestination+250.0)/600.0;
yfract = (600.0-yDestination)/600.0;
xStep = xfract*i;
yStep = yfract*i;
if (xStep >= 50){
thisX = xStep/50-5;
}else{
thisX=5;
}
if (yStep >= 50){
thisY = 11-yStep/50 + 1;
}else{
thisY = 11;
}
thisX = abs(thisX);
if (bubbleAt(thisX, thisY)!=nullptr){
endX = xfract*i;
endY = yfract*i;
i = 600;
std::cout << "collision at x: "<<thisX<< " y: "<<thisY<<std::endl;
std::cout << "collision at x: "<<xStep<< " y: "<<yStep<<std::endl;
std::cout << graphicalGameBoard_.width() << " " << graphicalGameBoard_.height()<<std::endl;
removeBubble(thisX, thisY);
graphicalGameBoard_.removeBubble(thisX, thisY);
endY = 600-endY;
}
}
graphicalGameBoard_.animateSplash(graphicalGameBoard_.width()/2, graphicalGameBoard_.height(), endX, endY);
I'm trying to split the steps into small fractions and check if the current step has a bubble in it until the water drop reaches the end or finds a bubble.
This works on my only one of my sides in terms of calculating, but the animation is off the mark and right side (x>250) collision detection doesn't work at all for some reason (it hits seemingly random bubbles at impossible locations on the right side).
Edit^2: Here are things I've tried in order to work with the actual collision detection of QT:
Within splashanimation.cpp, where the water drop is drawn using
SplashAnimation::SplashAnimation(GameBoard* scene, QPointF startPoint, QPointF endPoint):
QVariantAnimation(0),
scene_(scene),
item_()
{
scene_->addItem(&item_);
// The animation runs for the given duration and moves the splash
// smoothly from startpoint to endpoint.
setDuration(2000);
setKeyValueAt(0, QPointF(startPoint));
setKeyValueAt(1, QPointF(endPoint));
}
SplashAnimation::~SplashAnimation()
{
scene_->removeItem(&item_);
}
void SplashAnimation::updateCurrentValue(QVariant const& value)
{
item_.setPos(value.toPointF());
}
where scene is QGraphicsScene, and the parent of this contains the bubbles.
I've tried this on both the gameboard.cpp (which is parent for bubbles and the animation) and splash.cpp (which animates the water drop), but both give me the same compilation errors.
QGraphicsItem::QGraphicsItem();
gives
error: cannot call constructor ?QGraphicsItem::QGraphicsItem? directly [-fpermissive]
QGraphicsItem::QGraphicsItem();
^
QList<QGraphicsItem *> list = collidingItems() ;
gives error: ?collidingItems? was not declared in this scope
QList<QGraphicsItem *> list = collidingItems() ;
^
QList<QGraphicsItem *> list = QGraphicsItem::collidingItems() ;
gives error: cannot call member function ?QList<QGraphicsItem*> QGraphicsItem::collidingItems(Qt::ItemSelectionMode) const? without object
QList<QGraphicsItem *> list = QGraphicsItem::collidingItems() ;
^
I also tried adding arguments, but nothing I had the mind to try worked any better.
In this answer I am going to give you some recommendations that you use to implement the solution:
Avoid using the following instruction, use the signals that is one of the most powerful elements of Qt and that the event loop does the work.
while (animations_.state() == QAbstractAnimation::Running)
{
QCoreApplication::processEvents(QEventLoop::AllEvents);
}
QGraphicsScene works with coordinates that support the floating point, so the coordinates of the scene are handled with QPointF.
Using the above, if you are going to send point information use QPointF instead of int, int in the signals.
Use the methods that Qt provides, for example the following:
if (0 <= clickPosition.x() and clickPosition.x() <= GRID_SIDE*WIDTH and
0 <= clickPosition.y() and clickPosition.y() <= GRID_SIDE*HEIGHT)
It can be reduced to the following:
if(sceneRect().contains(event->scenePos()))
The advantage of that implementation is that it is more readable
I do not understand why you can not implement collidingItems, maybe it's the configuration of your .pro,
Use the following to add the gui module, core and widgets
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
Also to implement the animation use my previous answer
The complete and functional code can be found at the following link.

Trouble writing to 4D vector in C++ (no viable overloaded '=')

The issue I am facing is that via the openCV library I am reading in a series of images as their own "Mat" format: an image matrix.
Basically I need to write any pixel value that's > 0 as "true" to a 4D vector and any that == 0 as "false".
Why 4 dimensions?
vector<vector<vector<bool>>>pointVector;
The 3 vector levels refer to X,Y,Z axes. Bool is just the true/false. The images are Y by Z and are stacked in 3D along axis X.
Basically we have a series of images representing points that are stacked in 3D.
(Poor explanation? Probably)
Anyway, the issue comes in my function to read the points in a single photo then write them out to the 4D vector.
Note: xVal is a global storing the ID number of the photo addressed. It's used for the X dimension (layers of images).
Int lineTo3DVector (Mat image)
{
// Takes in matrix and converts to 4D vector.
// This will be exported and all vectors added together into a point cloud
vector<vector<vector<bool>>>pointVector;
for (int x=0; x<image.rows; x++)
{
for (int y = 0; y<image.cols; y++)
{
if((image.at<int>(x,y)) > 0)
{
pointVector[xVal*image.cols*image.rows + x*image.cols + y] = true;
}
}
}
}
I haven't finished writing all of the function because the if statement intended to write pointVector at address xVal, x, y with bool 'true' throws up an error saying:
No viable overloaded '='
Any idea what's going wrong? I've scoured the web and given myself a headache trying to dig up info (yeah, noob in the deep-end again) so any suggestions would be appreciated.
You're accessing only the first vector (the outer one), without actually accessing any of the vectors inside.
The syntax would be pointVector[x][y][z] = true, where x, y and z are the values you want to use to access the three nested vectors.
What you want is:
pointVector[xVal][x][y] = true
What you were using is a way to access a 3D array that is laid out in memory as a 1D array, but it's not what you want in your case.
Make sure you don't go out of bounds
Make sure the elements you are accessing actually exist! If the code you have shown is the actual code, pointVector will have no elements when you try to use it.
To fix that, you have to resize all the vectors (outer and inner). This can get cumbersome, and you may want to go with the 1D approach, i.e. allocate a large, one-dimensional bool array and access it using the method you were using (largeArray[xVal*image.cols*image.rows + x*image.cols + y]).
1D approach
In the following code numberOfValues is the maximum number of elements you will access.
int lineTo3DVector (Mat image)
{
// Takes in matrix and converts to 4D vector.
// This will be exported and all vectors added together into a point cloud
std::vector<bool> pointVector;
pointVector.resize(numberOfValues);
for (int x=0; x < image.rows; x++)
{
for (int y = 0; y < image.cols; y++)
{
if(image.at<int>(x,y) > 0)
{
pointVector[xVal*image.cols*image.rows + x*image.cols + y] = true;
}
}
}
// Return whatever.
}

filling an area of a matrix with characters

I have created a matrix using 2D vectors. The code I used is
int RC=50;
vector<vector<int> > matrix;
vector<int>row;
///////////Building Grid//////////////////
for(int i=0;i<RC;i++)
{
for(int j=0;j<RC;j++)
{
row.push_back(0);
}
matrix.push_back(row);
}
//////////Printing Grid///////////////////
for(int i=0;i<RC;i++)
{
for(int j=0;j<RC;j++)
{
cout<<matrix[i][j]<<" ";
}
cout<<endl;
}
The output of the above code is
Now what I want is to fill a block of size 6x6 inside the matrix with '$' or any character by inputting the bottom left location of the block. For example if i gave the location as (10,4), then I would like to place a block of '$' (size 6x6) whose bottom left co-ordinates are (10,4).
EDIT-1
I added the code
int si=3;
int sy=3;
for(int i=0;i<RC;i++)
{
for(int j=0;j<RC;j++)
{
if(i>=si && i<=si+6 && j>=sy && j<=sy+6)
{
matrix[i][j]=1;
}
else
{
matrix[i][j]=0;
}
}
}
and I got the output as
I am reading the co-ordinates as the top left ones, what should I do to read the co-ordinates as the bottom left ones and build the block from there?
You need to tackle the problem logically and break down the steps you need to solve it. You're staring at a big block of zeros and that isn't going to help. So, walk through it with pseudo code and a handy, dandy piece of paper and pencil.
Ask smaller questions about the larger problem at hand. How do you go from bottom left coordinate to the coordinate you wish to start with? How do you determine when to stop? Do I understand what I just did? If not why don't I understand it?
Baby step by baby step while you're learning. Take the time to understand why something either worked the way you wanted it to or failed to work. Do this and you'll be a much better coder for it.

QGraphicsScene.itemAt() only returns zero and whole scene is slow

I am trying to create a dot matrix in a QGraphicsScene. I have a button, which fills a 2d-array with random numbers and than i will paint a pixel on every position where the array has a 0.
Now, when I wants to generate the matrix again i want to check every pixel and array-field whether they are empty or not. If the pixel is empty and the array not, i want to set a pixel. If there is a pixel but the array is empty i want to remove the pixel. Now the problem is, the function itemAt() always returns 0 even if i can clearly see existen pixels.
What is my problem?
//creating the scene in the constructor
QPainter MyPainter(this);
scene = new QGraphicsScene(this);
ui.graphicsView->setScene(scene);
//generating matrix
void MaReSX_ClickDummy::generate(void)
{
QGraphicsItem *item;
int x, y;
for(x=0; x< 400; x++)
{
for(y=0; y<400; y++)
{
dataArray[x][y] = rand()%1001;
}
}
for(x=0; x < 400; x++)
{
for(y=0; y<400; y++)
{
item = scene->itemAt(x, y, QTransform());//supposed to check whether there is already a pixel on that place but always returns zero
if(dataArray[x][y] == 0 && item == 0)
scene->addEllipse(x, y, 1, 1);
//does not work
else if(dataArray[x][y] != 0 && item != 0)
scene->removeItem(item);
}
}
}
Also the generating of the matrix is very slow. Since the matrix is supposed to show realtime data later, it should run as fast as possible. (and the scene will be bigger than 400*400 pixels like now). Any ideas how to improve the code?
And can somebody explain what the third parameter of itemAt() is supposed to do?
Thank you!
400x400 'dot matrix' is up to 16000 dots, or up to 2500 characters, which quite big.
The QGraphicsScene is designed to handle a small number of large shapes, and was probably not designed to handle this many shapes. Using it in this way to create thousands of identical tiny 'pixel' objects is incredibly inefficent.
Could you create a 400x400 bitmap(QBitmap?) instead, and set the individual pixels that you want?
You are supposed to be using a QGraphicsPixmapItem instead of an array of dots!