I am new to c++ and Opencv.
I am trying to detect the mouse coordinates when I click the left button of the mouse, and if such coordinates are within a certain area of the image, it draws a rectangle using the current mouse coordinates as the top-left vertex.
Here is the implementation:
void CallBackFunc(int event, int x, int y, int flags, void * userdata)
{
if(event == EVENT_LBUTTONDOWN || event == EVENT_LBUTTONUP)
{
mouseX=x;
mouseY = y;
`
if(( mouseX >= 0 && mouseX <= 130) && ( mouseY >= 22 && mouseY <=301))
{
rectangle(img,Point(mouseX, mouseY),Point(mouseX+30, mouseY+ 40),Scalar(0,0,0),1,8);
}
}
It will store the coordinates, but it seems that it never executes the inner if statement.
Related
I'm adapting some skeleton code to learn how OpenGL works and have in SphericalCameraManipulator.cpp which allows me to pan and tilt the camera while I hold down right mouse:
void SphericalCameraManipulator::handleMouseMotion(int x, int y)
{
//Motion
float xMotion = (float)x - previousMousePosition[0];
float yMotion = (float)y - previousMousePosition[1];
if(reset)
{
xMotion = yMotion = 0.0;
reset = false;
}
this->previousMousePosition[0] = (float)x;
this->previousMousePosition[1] = (float)y;
//Right Button Action
if(this->currentButton == GLUT_RIGHT_BUTTON && this->currentState == GLUT_DOWN)
{
this->pan -= xMotion*this->panTiltMouseStep ;
this->tilt += yMotion*this->panTiltMouseStep ;
}
//Enforce Ranges
this->enforceRanges();
}
I deleted the left mouse action as I don't want it to control the camera, and it now actions a command in the main code body.
//Left Button Action
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
... //game action
}
My problem is that when I click the left mouse, the press of the right mouse is cancelled, and I must release and repress the right mouse to continue controlling the camera.
Is there a way to prevent this from happening? It interrupts the flow of the game. I'm using GLUT
Rabbid76's comment saying there is no mouse hold event set me on the right path.
I wrote a small function that simply recorded the last state of mouse button 2 (the 'camera look around' button):
void SphericalCameraManipulator::handleMouse(int button, int state)
{
this->currentButton = button;
this->currentState = state;
//to enable mouse look around
if (this->currentButton == 2) //right mouse
this->lastLookState = this->currentState;
if(this->currentState == GLUT_UP)
{
reset = true;
}
}
This mean even when the current state was regarding the left mouse button (game action) it was still possiblew to look around since a 'mouse two button up' event had not occured:
this->currentButton = 2;
this->currentState = 1;
I have an object that I want to be able to move. I want it to move only if i click within in, then drag my mouse to a place, then upon release, it starts moving towards it. so if i click inside it, I can move my mouse anywhere as much as I want while holding mouse button, but only when I release does it start to move.
Currently, the best ive been able to do is make the object follow (a couple seconds behind btw, NOT on the mouse position) as long as im holding the mouse button and moving it. it doesnt matter where I start the click from, as long as I click and move, the object moves towards it as long as im holding the mouse button. any other attempts leave the object staying still/not moving at all.
void mousemotion(int x, int yc){
globals.mouse_x = x;
globals.mouse_y = HEIGHT - yc;
}
and
int main(int argc, char** argv){
glutInit(&argc, argv);
....
//glutMouseFunc(processMouse);
glutMotionFunc(mousemotion);
are the only mouse functions/callbacks that are currently being used to allow the result above. I have tried things like adding a glutMouseFunc callback but from changing the state parameter in it produces bad results. E.G:
//glutMouseFunc callback
void processMouse(int button, int state, int x, int yc){
if ( state == GLUT_UP){
globals.centre_x = globals.mouse_x;
globals.centre_y = globals.mouse_y;
}
GLUT_DOWN doesnt change the main behaviour, but when the object is in motion, and I just click once, the object will snap to the position it was going to. GLUT_UP just makes it so once I release the mouse, the object will immediately snap to the position it was going. These behaviours make sense as to they are behaving the way they are, but I cant manipulate it to work the way I want to. I also made a function to check if a point is inside the object but I dont know where its applicable
bool inside(int x, int y){
if(x >= globals.centre_x - 20
&& x <= globals.centre_x +20
&& y >= globals.centre_y - 20
&& y <= globals.centre_y+ 20){
return true;
}
else
return false;
}
pressumably it would be used inside once of the mouse functions, using the x and y mouse coordinates as parameters.
all the drag and drop examples Ive seen online involve immediate dragging of the object, i.e. click on object and object follows the exact x,y mouse coordinates as you move it around, but I want to make it so only when I let go of the mouse will the object start to move.
Any Help appreciated. let me know if i can clarify anything. thanks
I do not use GLUT but Based on these:
GLUT docs
GLUT mouse button down
To detect mouse event type You need to do something like this:
//glutMouseFunc callback
int state0l=GLUT_UP; // last left mouse buttons state
int state0r=GLUT_UP; // last right mouse buttons state
void processMouse(int button, int state1, int x, int y)
{
if (button == GLUT_LEFT_BUTTON)
{
// decode and handle the mouse events by type
if ((state0l == GLUT_UP )&&(state1 == GLUT_DOWN)) // mouse down (click)
{
// here do your stuff
}
if ((state0l == GLUT_DOWN)&&(state1 == GLUT_DOWN)) // mouse move while clicked
{
// here do your stuff
}
if ((state0l == GLUT_DOWN)&&(state1 == GLUT_UP )) // mouse up (release)
{
// here do your stuff
}
if ((state0l == GLUT_UP )&&(state1 == GLUT_UP )) // mouse move without buttons
{
// here do your stuff
}
// store actual buttons state for next time
state0l = state1;
}
if (button == GLUT_RIGHT_BUTTON)
{
// decode and handle the mouse events by type
if ((state0r == GLUT_UP )&&(state1 == GLUT_DOWN)) // mouse down (click)
{
// here do your stuff
}
if ((state0r == GLUT_DOWN)&&(state1 == GLUT_DOWN)) // mouse move while clicked
{
// here do your stuff
}
if ((state0r == GLUT_DOWN)&&(state1 == GLUT_UP )) // mouse up (release)
{
// here do your stuff
}
if ((state0r == GLUT_UP )&&(state1 == GLUT_UP )) // mouse move without buttons
{
// here do your stuff
}
// store actual buttons state for next time
state0r = state1;
}
}
As you can see I just inspect last and actual state of the buttons to detect 4 possibilities +/- the same as in the link I gave you before:
simple low level Drag&Drop example in C++
I just have q0,q1 instead of the state0,state1 when you inspect the methods like: editor::mov,add_kruh,add_stvorec,... they all use this same technique (but only those events they use of coarse).
Do selection detection in your mouse callback on button-down
Set up animation parameters (start & end position + duration) in your mouse callback on button-up
Interpolate animation positions in a timer callback & update selected position
All together (right-click to add rectangles):
#include <GL/glut.h>
// https://glm.g-truc.net/
#include <glm/glm.hpp>
#include <vector>
struct Rect
{
glm::vec2 pos;
glm::vec2 dim;
bool IsInside( glm::vec2 point ) const
{
const bool inX = pos.x < point.x && point.x < pos.x + dim.x;
const bool inY = pos.y < point.y && point.y < pos.y + dim.y;
return inX && inY;
}
};
// rect list & selection
std::vector< Rect > rects;
int selected = -1;
// animation state
int timeBeg = -1;
int timeEnd = -1;
glm::vec2 src;
glm::vec2 dst;
void mouse( int button, int state, int x, int y )
{
if( GLUT_RIGHT_BUTTON == button )
{
// add rect
if( GLUT_UP == state )
{
rects.push_back( Rect{ glm::vec2( x, y ), glm::vec2( 60, 60 ) } );
glutPostRedisplay();
}
return;
}
if( GLUT_LEFT_BUTTON == button && ( timeBeg < 0 || timeEnd < 0 ) )
{
// select rect
if( GLUT_DOWN == state )
{
for( size_t i = 0; i < rects.size(); ++i )
{
if( !rects[i].IsInside( glm::vec2( x, y ) ) )
continue;
selected = i;
glutPostRedisplay();
return;
}
}
// finish select
if( GLUT_UP == state && selected >= 0 )
{
timeBeg = glutGet( GLUT_ELAPSED_TIME );
timeEnd = timeBeg + 1000;
src = rects[ selected ].pos;
dst = glm::vec2( x, y );
}
return;
}
}
void timer( int value )
{
glutTimerFunc( 16, timer, 0 );
// don't repaint if we aren't animating
if( timeBeg < 0 || timeEnd < 0 || selected < 0 )
return;
const int timeCur = glutGet( GLUT_ELAPSED_TIME );
if( timeCur > timeEnd )
{
// animation done
timeBeg = -1;
timeEnd = -1;
selected = -1;
glutPostRedisplay();
return;
}
float pct = ( timeCur - timeBeg ) / static_cast< float >( timeEnd - timeBeg );
rects[ selected ].pos = glm::mix( src, dst, pct );
glutPostRedisplay();
}
void display()
{
glClearColor( 0, 0, 0, 1 );
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
double w = glutGet( GLUT_WINDOW_WIDTH );
double h = glutGet( GLUT_WINDOW_HEIGHT );
glOrtho( 0, w, h, 0, -1, 1 );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
for( size_t i = 0; i < rects.size(); ++i )
{
if( selected == i )
glColor3ub( 255, 0, 0 );
else
glColor3ub( 255, 255, 255 );
const Rect& rect = rects[i];
glRectf( rect.pos.x, rect.pos.y, rect.pos.x + rect.dim.x, rect.pos.y + rect.dim.y );
}
glutSwapBuffers();
}
int main( int argc, char** argv )
{
glutInit( &argc, argv );
glutInitWindowSize( 800, 600 );
glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE );
glutCreateWindow( "GLUT" );
glutMouseFunc( mouse );
glutTimerFunc( 0, timer, 0 );
glutDisplayFunc( display );
glutMainLoop();
return 0;
}
Im kinda new to glut and opengl and I'm trying to make camera movement on mouse movement but when trying to get the mouse position on the screen I assumed the method you want to pass the x and y to should just be referenced in the glutPassiveMotionFunc() parameter. But I'm getting errors when trying to give the function the CameraMove method. I know I'm passing the method wrong but Im not sure how.
void helloGl::CameraMove(int x, int y)
{
oldMouseX = mouseX;
oldMouseY = mouseY;
// get mouse coordinates from Windows
mouseX = x;
mouseY = y;
// these lines limit the camera's range
if (mouseY < 60)
mouseY = 60;
if (mouseY > 450)
mouseY = 450;
if ((mouseX - oldMouseX) > 0) // mouse moved to the right
angle += 3.0f;`enter code here`
else if ((mouseX - oldMouseX) < 0) // mouse moved to the left
angle -= 3.0f;
}
void helloGl::mouse(int button, int state, int x, int y)
{
switch (button)
{
// When left button is pressed and released.
case GLUT_LEFT_BUTTON:
if (state == GLUT_DOWN)
{
glutIdleFunc(NULL);
}
else if (state == GLUT_UP)
{
glutIdleFunc(NULL);
}
break;
// When right button is pressed and released.
case GLUT_RIGHT_BUTTON:
if (state == GLUT_DOWN)
{
glutIdleFunc(NULL);
//fltSpeed += 0.1;
}
else if (state == GLUT_UP)
{
glutIdleFunc(NULL);
}
break;
case WM_MOUSEMOVE:
glutPassiveMotionFunc(CameraMove);
break;
default:
break;
}
}
Assuming helloGl is a class. Then the answer is, you can't. A function is not the same as a method. The thing is that glutPassiveMotionFunc() expects:
void(*func)(int x, int y)
But what you're trying to give it is:
void(helloGl::*CameraMove)(int x, int y)
In other words a thiscall. This doesn't work because a thiscall basically has an additional hidden argument in contrast to a cdecl. In all it's simplicity you can imagine your CameraMove() as:
void CameraMove(helloGl *this, int x, int y)
As you can see, that isn't the same. So the solution is then to move CameraMove() out of your helloGl class or making the method static.
Basically, I'm trying to rotate a square around 2 points at the same time.
Here, when mouse is going left or right I'm trying to rotate the square around it's center, and when mouse is going up or down, I'm rotating around any other point (50:100 here). However, my square is jumping around the screen, and when I'm trying to rotate around the center only, it continues to rotate around 50:100.
Any suggestions how to fix that?
#include <SFML/Graphics.hpp>
using namespace sf;
Event evt;
int main(int argc, char* argv)
{
RenderWindow window(VideoMode(600, 600), "test");
RectangleShape test(Vector2<float>(20.0f, 20.0f));
test.setFillColor(Color::Red);
test.setPosition(300, 300);
test.setOrigin(10, 10);
Clock deltaTime;
Clock timer;
timer.restart();
int mouseX = 0, mouseY = 0;
int curMouseX = 0, curMouseY = 0;
float offset = 100;
bool moving = false;
while (window.isOpen())
{
while (window.pollEvent(evt)) {
switch (evt.type)
{
case Event::MouseMoved:
curMouseX = mouseX;
curMouseY = mouseY;
mouseX = evt.mouseMove.x;
mouseY = evt.mouseMove.y;
moving = true;
break;
}
}
float elaspedTime = deltaTime.restart().asSeconds();
if (curMouseX != mouseX && moving) {
test.setOrigin(10, 10);
test.rotate(360 * elaspedTime);
// test.setOrigin(50, 100); Tried this to avoid jumping. When uncommented, doesn't rotate around the center.
}
if (curMouseY != mouseY && moving) {
test.setOrigin(50, 100);
test.rotate(60 * elaspedTime);
}
window.clear();
window.draw(test);
window.display();
moving = false;
}
return 0;
}
Instead of using the sf::Transfomable class inherited from your shape, create a sf::Transform for it and use rotate (float angle, const Vector2f ¢er)
You just have to store your mouse position each time it moves in a sf::Vector2f
So i'm trying to capture mouse dragging in my OpenGL application. I've done the following so far:
glfwSetMouseButtonCallback(window, mouse_callback);
static void mouse_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT) {
double x;
double y;
glfwGetCursorPos(window, &x, &y);
if (previous_y_position - y > 0)
{
camera_translation.y -= 1.0f;
previous_y_position = y;
}
else
{
camera_translation.y += 1.0f;
previous_y_position = y;
}
}
}
The problem with this though is if I would like to zoom in I need to move my mouse upwards and then click repeatedly. For some reason if I press down on the left mouse button and drag upwards it does nothing.
In cursor_pos_callback, just confirm if the button is pressed, and that works.
void mouse_cursor_callback( GLFWwindow * window, double xpos, double ypos)
{
if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_RELEASE)
{
return;
}
// `write your drag code here`
}
mouse_callback is stateless. It receives events, momentary "actions".
You need to make your program to "remember" that mouse button is pressed. So that when button is pressed in a frame 1, you can refer to this information in all the frames after that and before mouse button is released.
The simple way is to flip a boolean flag on press/release:
static void mouse_callback(GLFWwindow* window, int button, int action, int mods)
{
if (button == GLFW_MOUSE_BUTTON_LEFT) {
if(GLFW_PRESS == action)
lbutton_down = true;
else if(GLFW_RELEASE == action)
lbutton_down = false;
}
if(lbutton_down) {
// do your drag here
}
}
Schematically:
state released pressed released
timeline -------------|------------------------------|---------------
^ ^
mouse_callback calls GLFW_PRESS GLFW_RELEASE
The hard way is to use a state machine (especially if you need more complicated combinations of states of input controllers).