I have a program that is taking input from an external source (right now, a joystick), and then plotting it on a graph. The graph displays the last 60 frames of data, which is about 1-2 seconds.
here is the data input:
nextDataPoint(double x){
if (x > max){ max = x; }
if (x < min){ min = x; }
dataInput.enqueue(x) //dataInput is a QQueue<double>
while (dataInput.size() > 60){
dataInput.dequeue();
}
update(); //this triggers the paint event
}
here is the graphing function
graph function:
//this draws the min line and the max line
QPainter painter(this);
int lineDist = 25;
QPen myPen(Qt::black, 3);
QPoint maxText(10,20);
painter.drawText(maxText, "max");
QPoint maxLineLeft(0, lineDist);
QPoint maxLineRight(width(), lineDist);
painter.drawLine(maxLineLeft, maxLineRight);
QPoint minText(10, height()-10);
painter.drawText(minText, "min");
QPoint minLineLeft(0, height()-lineDist);
QPoint minLineRight(width(), height()-lineDist);
//this draws the actual graph
myPen.setColor(Qt::blue);
myPen.setWidth(2);
painter.setPen(myPen);
double dist = (double)(heigh() - 2*lineDist);
int stepSize = (int)((double)width() / 60.0);
int heightStep = (max-min)/dist;
double x;
QPoint lastPoint(0,0);
QPoint nextPoint(0,0);
int i = 0;
if (!dataInput.empty()){ //checks that there is data
if (dataInput.size() < 60) { //ignoring for sake of brevety
} else {
x = dataInput.at(i);
x = max - x; // this inverts the data, necessary because (0,0) is the upper left corner
x = (x-min)/heightStep;
nextPoint.setX(0);
nextPoint.setY(x+lineDist);
for (i = 1; i < 60; i++){
x = dataInput.at(i);
x = max - x;
x = (x-min)/heightStep;
lastPoint = nextPoint;
nextPoint.setX(i*stepSize);
nextPoint.setY(x+lineDist);
painter.drawLine(lastPoint, nextPoint);
}
}
}
So, with one joystick that I am testing with, this program works without issue. As I move the joystick, the program draws the blue line within the bounds listed on the screen. x is input as a number between 0 and 65535, and after moving the joystick around a little bit the system recognizes that as the max and the min, and then proceeds to function as expected.
The second "joystick" is less of a joystick and more of a pressure sensor. This outputs either x = 1023 or x is some number between 5 and 9. In this case however, the blue line appears on the same level as the max line, or when the data output is x in the single digits, the blue line appears below min. I haven't been able to figure out why this would be the case, the first joystick can also produce results of 0, but it never goes below the minimum line. What might be causing this particular issue?
Two changes were needed to correct the issues.
First, stepSize and heightStep were both changed from int to double.
second, the section
x = dataInput.at(i);
x = max - x;
x = (x-min)/heightStep;
nextPoint.setX(0);
nextPoint.setY(x+lineDist);
for (i = 1; i < 60; i++){
x = dataInput.at(i);
x = max - x;
x = (x-min)/heightStep;
lastPoint = nextPoint;
nextPoint.setX(i*stepSize);
nextPoint.setY(x+lineDist);
painter.drawLine(lastPoint, nextPoint);
}
was changed to:
x = dataInput.at(i);
x = (x-min)/heightStep;
nextPoint.setX(0);
nextPoint.setY(dist-x+lineDist);
for (i = 1; i < 60; i++){
x = dataInput.at(i);
x = (x-min)/heightStep;
lastPoint = nextPoint;
nextPoint.setX(i*stepSize);
nextPoint.setY(dist-x+lineDist);
painter.drawLine(lastPoint, nextPoint);
}
This solved the issue and made the system always draw the data between the min and max lines.
Related
Traditionally, when processing an image, interpolation is done to the pixel value. My case is I need to generate a remap (on PC) to be put in an embedded system with a camera for further processing, such that any processing algorithms could directly refer to the remap instead of having to process every frame beforehand. Like so (ofc not written like this in application, just a demo):
struct Point { //A pixel on the image
int x, y
} original, corrected;
//I want every entry in this remap to have a valid value
float remap[width][height][2] = ...; //Contains the new pixel coordinates of each pixel
//I want the processes in the embedded system to be able to do this with every pixel
//But now it is not possible as not every pixel has a corresponding mapX and mapY
corrected.x = remap[original.x][original.y][0]; //mapX
corrected.y = remap[original.x][original.y][1]; //mapY
One of processes to generate the remap is radial distortion correction using OpenCV. As OpenCV uses an inverse map dst(x, y) = src(mapX(x, y), mapY(x, y)), I inversed it again such that dst(mapX(x, y), mapY(x, y)) = src(x, y). But then some x, y does not have a corresponding mapX, mapY after the correction.
I need every x, y to have a corresponding mapX, mapY for the processes on the embedded system to work properly. How can I interpolate the pixel coordinates instead of the pixel value?
So far I tried simply averaging out mapX, mapY values in the surrounding area, but did not work well.
for (int i = 0; i < parameters.width * parameters.height; ++i) {
if (!status[i]) { //If no corresponding mapX, mapY
double avgX = 0, avgY = 0;
int count = 0;
for (int y = -5; y < 5; ++y) { //A square surrounding the pixel being interpolated
for (int x = -5; x < 5; ++x) {
int num = std::min(std::max(0, i + y * parameters.width + x), parameters.width * parameters.height);
if (status[num]) { //If this pixel has a corresponding mapX, mapY
avgX += mapX[num];
avgY += mapY[num];
++count;
}
}
}
//If at least 1 pixel in the surrounding area has a corresponding mapX, mapY
if (avgX != 0 || avgY != 0) {
avgX /= count;
avgY /= count;
mapX[i] = avgX;
mapY[i] = avgY;
status[i] = true;
}
}
}
warning probably
int num = std::min(std::max(0, i + y * parameters.width + x), parameters.width * parameters.height);
must be
int num = std::min(std::max(0, i + y * parameters.width + x), parameters.width * parameters.height - 1);
because of for (int i = 0; i < parameters.width * parameters.height; ++i) (I mean i < parameters.width * parameters.height rather than i <= parameters.width * parameters.height)
avgX and avgY are modified only if (status[num]) is true, are some entries of status containing true before to do the overall for ?
I'm trying out some sample code for a bigger project, and I'm having trouble getting my rectangle to bounce between two lines.
function draw() {
print(frameCount)
background(255)
var x = 150 + frameCount;
rect(x,200,15,15);
line(150,0,150,400);
line(250,0,250,400);
if (x >= 250) {
background(255)
x = 350-frameCount;
rect(x,200,15,15);
line(250,0,250,400);
line(150,0,150,400);
} if (x <= 145) {
background(255)
x = 145 + (frameCount % 100);
rect(x,200,15,15);
line(250,0,250,400);
line(150,0,150,400);
}
}
I'm getting the feeling that after the first instance, it's disregarding the original if statement, which dictates a bounce to the left. I'm really not sure what's going wrong, and any help would be appreciated.
You probably just want to store the current position and speed in a set of variables, and then move the rectangle based on those. Here's an example:
var x = 0;
var speed = 1;
function draw(){
x += speed;
if(x < 0 || x > width){
speed *= -1;
}
background(64);
line(x, 0, x, height);
}
I've written a tutorial on this available here. That's for regular Processing, but the ideas are the same in P5.js.
I am trying to get my tokens on a board game to fall slowly. Right now, they fall, but they fall so fast. How could I implement the timer function in my code? Right now I do a loop, that updates the y coordinate of glTranslate. But it is still too fast! the top y is the y coordinate where I press on the screen, and the bottomy is the coordinates of the lowest open spot for a token.
col =0;
double bottomy = 0;
int row = 0;
circlex = (double)x / width ;
circley = (double)y / height ;
row = board.getRow(col) + 1;
bottomy = 500 - (25*row);
for( double topy = y ; topy <= bottomy; topy += 2 ){
glTranslatef(circlex, circley, 0.0f);
circley += .0000000000000000001;
display();
}
r = board.makeMove(col);
You can use glutTimerFunc to execute a function at a regular time period. This has the signature
void glutTimerFunc(unsigned int msecs,
void (*func)(int value),
value);
For example if your drawing function was
void UpdateTokens(int time);
Then you could call an update every 0.5 seconds with the following call (where current_time was the current simulation time)
glutTimerFunc(500, UpdateTokens, current_time);
For more precise timing, I would recommend using <chrono> instead, and performing your timing using things like std::chrono::duration with a std::chrono::steady_clock.
The actual problem here is how glut works. Basically, the user only gets a image presented at the end of the main loop. As long as you do not return from the mouse function, nothing is presented on screen. You can solve the problem by transferring the work to the display function and distribute the translation across multiple frames:
global variables:
double circlex = 0, circley = 0, bottomy = 0;
bool isfalling = false;
int topy = 0;
mouse_func:
if (isfalling == false) //Prevents the user from clicking during an animation
{
circlex = (double)x / width ;
circley = (double)y / height ;
int row = board.getRow(col) + 1;
bottomy = 500 - (25*row);
topy = y;
isfalling = true;
}
display_func:
if (isfalling)
{
circley += .0000000000000000001;
topy += 2;
if (topy >= bottomy)
isfalling = false;
}
glTranslatef(circlex, circley, 0.0f);
display();
I'm hoping someone out there might have an idea on how I could better solve this problem I've created for myself :) I'm currently looking for a way to program this logic:
Imagine I have a control slider, that a user controls and goes from 0 to 255, and imagine I have a timing slider, from 0 milliseconds to 20,000 milliseconds.
Now, if I set the timing slider to 20,000, and move the control slider from 0 to 255, I would expect that the code will output a transition point between 0 to 255 over 20 seconds. I have code that does this fine, and it will be attached below.
However, lets say 10 seconds into that transition period the user moves the control slider from the 255 back to 0. At 10 seconds in, the transition point, x, should be at 127. What I want to happen is for the x value to move over the remaining 10 seconds to the new control slider point, in this case, 0. Ideally this should work for any number of movements over that 20 second period.
Once the x reaches the control slider point, the transitioning code deactivates until the next movement.
Here's the code that handles the first part of the problem I'm trying to solve:
class Fader {
public:
float newFaderValueSetTime;
float newFaderValue;
bool transitionInMotion;
float lastReturnedValueWhenNewFaderValueWasSet;
bool newFaderValueSet;
float lastOutputValue;
Fader(void) {
lastReturnedValueWhenNewFaderValueWasSet = 0;
newFaderValue = 0;
lastOutputValue = 0;
transitionInMotion = false;
}
int getValue(float delayAmount) {
float currentTime = ofGetElapsedTimeMillis() ;
float timePassedSinceNewFaderValue = currentTime - newFaderValueSetTime;
if(timePassedSinceNewFaderValue >= delayAmount) {
transitionInMotion = false;
}
if(transitionInMotion) {
lastOutputValue = ofMap(timePassedSinceNewFaderValue, 0, delayAmount, lastReturnedValueWhenNewFaderValueWasSet, newFaderValue);
} else {
lastOutputValue = newFaderValue;
}
return lastOutputValue;
}
void setFaderValue(int val, float delayAmount) {
if(delayAmount > 0 && !transitionInMotion) {
transitionInMotion = true;
newFaderValueSetTime = ofGetElapsedTimeMillis();
lastReturnedValueWhenNewFaderValueWasSet = lastOutputValue;
}
newFaderValue = val;
}
};
This is in c++ using OpenFrameworks, hence the of prefix for some of the functions. Anyway, I hope I've been specific enough about the problem.
The main point of code that is at issue, I think is the way the mapping of value ranges functions - for example, take this line:
lastOutputValue = ofMap(timePassedSinceNewFaderValue, 0, delayAmount, lastReturnedValueWhenNewFaderValueWasSet, newFaderValue);
This line takes the amount of time passed as the temporal position, makes it relative to delay amount, then remaps its the value from the lastReturnedValueWhenNewFaderValueWasSet to the newFaderValue.. e.g.,
If at time of transition, the fader value was at 0, and moves to 255, then
lastReturnedValueWhenNewFaderValueWasSet = 0, and newFaderValue = 255;
However, at the 10 second mark, the lastOutputValue will be 127, and if I then move the newFaderValue from 255 to 0, then lastReturnedValueWhenNewFaderValueWasSet will still be 0, and the mapping will be from 0 to 0, rather than from the current position of the transition point, x.
I hope this explains the logic a bit better. Cheers!
I've solved the problem I set out. Here is a rundown of the logic and the code for those looking for a solution to this sort of problem.
x will increase if the destination is greater than x
x will decrease if the destination is less than x
x is defined as the value set before the timer is initiated
if the timer is active if and only if
timer is greater than zero
The destination is greater than or less than x
The increase amount is defined as the distance between x, the destination, divided by the time left to reach the destination multiplied by the difference since the last time x was set.
e.g.
lets say x is 127, and destination is 200. The time remaining is 10,000 milliseconds
positive difference = 200-127 = 73 over 10,000
divided by the time remaining, multiplied by the time change since last update.
(200-127 / 10,000) * 60 (milliseconds since last update)
= amount to increment...
lets say x = 200 and the destination is 90. The time remaining is 10,000 milliseconds
positive difference is 200-90 = 110.
(110 / 10,000) * 60 (milliseconds since last update) = 0.66.. which is to be removed from x...
and because x is decreasing in this case, an additional calculation of (0.66 * -1) to produce the negative value.
And the code:
class Fader {
public:
float newFaderValueSetTime;
float destination;
float lastUpdateTime;
float x;
bool transitionInMotion;
Fader(void) {
transitionInMotion = false;
lastUpdateTime = -1;
x= 0;
destination = 0;
}
float positiveDifference(float x1, float y1) {
if(x1>y1) {
return x1-y1;
} else {
return y1-x1;
}
}
int getValue(float delayAmount) {
float currentTime = ofGetElapsedTimeMillis();
float timePassedSinceNewFaderValue = currentTime - newFaderValueSetTime;
if(timePassedSinceNewFaderValue >= delayAmount) {
transitionInMotion = false;
}
if(transitionInMotion) {
float timeRemaining = delayAmount - timePassedSinceNewFaderValue;
float diff = positiveDifference(x, destination);
float tempX = (diff / timeRemaining);
if(lastUpdateTime == -1) {
lastUpdateTime = currentTime;
} else {
tempX = tempX * (currentTime - lastUpdateTime);
}
if(destination > x) {
x = x + tempX;
} else if (destination < x) {
x = x + (tempX*-1);
}
} else {
x = destination;
}
if(x > 0) {
ofLogNotice("Output Value of fader is: " + ofToString(x));
}
lastUpdateTime = currentTime;
return x;
}
void setFaderValue(int val, float delayAmount) {
if(delayAmount > 0 && !transitionInMotion) {
transitionInMotion = true;
newFaderValueSetTime = ofGetElapsedTimeMillis();
lastUpdateTime = -1;
}
destination = val;
}
};
I'm writing a renderer using low-level SDL functions to learn how it all works. I am now trying to do polygon drawing, but I run into errors possibly due to my inexperience with C++. When running the code I get a munmap_chunk() - Invalid pointer error. Searching reveals that it is most likely due to free()-ing the memory twice. The error happens when returning from the function. I realize that the error comes from automatically free()ing memory which has been automatically free()d before, but I'm not experienced enough with C++ to spot the error. Any clues?
My code:
void DrawPolygon (const vector<vec3> & verts, vec3 color){
// 0. Project to the screen
vector<ivec2> vertices(verts.size());
for(int i = 0; i < verts.size(); i++){
VertexShader(verts.at(i), vertices.at(i));
}
// 1. Find max and min y-value of the polygon
// and compute the number of rows it occupies.
int miny = vertices[0].y;
int maxy = vertices[0].y;
for (int i = 1; i < 3; i++){
if (vertices[i].y < miny){
miny = vertices[i].y;
}
if (vertices[i].y > maxy){
maxy = vertices[i].y;
}
}
int rows = abs(maxy - miny) + 1;
// 2. Resize leftPixels and rightPixels
// so that they have an element for each row.
vector<ivec2> leftPixels(rows);
vector<ivec2> rightPixels(rows);
// 3. Initialize the x-coordinates in leftPixels
// to some really large value and the x-coordinates
// in rightPixels to some really small value.
for(int i = 0; i < rows; i++){
leftPixels[i].x = std::numeric_limits<int>::max();
rightPixels[i].x = std::numeric_limits<int>::min();
leftPixels[i].y = miny + i;
rightPixels[i].y = miny + i;
}
// 4. Loop through all edges of the polygon and use
// linear interpolation to find the x-coordinate for
// each row it occupies. Update the corresponding
// values in rightPixels and leftPixels.
for(int i = 0; i < 3; i++){
ivec2 a = vertices[i];
ivec2 b = vertices[(i+1)%3];
// find the number of pixels to draw
ivec2 delta = glm::abs(a - b);
int pixels = glm::max(delta.x, delta.y) + 1;
// interpolate to find the pixels
vector<ivec2> line (pixels);
Interpolate(a, b, line);
for(int j = 0; j < pixels; j++){
ivec2 p = line[j];
ivec2 cmpl = leftPixels[p.y - miny];
ivec2 cmpr = rightPixels[p.y - miny];
if(p.x < cmpl.x){
leftPixels[p.y - miny].x = p.x;
//leftPixels[p.y - miny] = cmpl;
}
if(p.x > cmpr.x){
rightPixels[p.y - miny].x = p.x;
//cmpr.x = p.x;
//rightPixels[p.y - miny] = cmpr;
}
}
}
for(int i = 0; i < leftPixels.size(); i++){
ivec2 l = leftPixels.at(i);
ivec2 r = rightPixels.at(i);
// y coord the same, iterate over x
int y = l.y;
for(int x = l.x; x <= r.x; x++){
PutPixelSDL(screen, x, y, color);
}
}
}
Using valgrind gives me this output (this is the first error it reports). Weirdly, the program recovers and keeps running with the expected result, apparently not getting the same error again:
==5706== Invalid write of size 4
==5706== at 0x40AD61: DrawPolygon(std::vector<glm::detail::tvec3<float>, std::allocator<glm::detail::tvec3<float> > > const&, glm::detail::tvec3<float>) (in /home/actimia/prog/dgi14/lab3/ThirdLab)
==5706== by 0x409C78: Draw() (in /home/actimia/prog/dgi14/lab3/ThirdLab)
==5706== by 0x409668: main (in /home/actimia/prog/dgi14/lab3/ThirdLab)
I think my previous post on similar topic would be useful.
https://stackoverflow.com/a/22658693/2724703
From your Valgrind report, it look like your program is doing memory corruption due to overflow. This does not seems like "double free" error(this is overflow scenario). You have mentioned that sometime valgrind is not reporting any error this makes this problem more difficult. However there is certainly a memory corruption and you must fix them. Memory error sometime occur intermittent due to various reason(different input parameter, multi-threaded, change of execution sequence).