Computer graphics to achieve mouse drag primitives

Computer graphics to achieve mouse drag primitives

Problem description

When it is necessary to drag primitives in computer graphics, the key is how to judge whether the mouse is dragging and the movement of the mouse when it is dragged

  1. Determines whether the mouse is pressed inside the element or moved inside the element
  2. Confirm the movement of the mouse, click the element, and the origin (anchor point) of the element will not blink to the position of the cursor

The following variables are known

bool isContained reflects whether the current position of the mouse is inside the element. true means inside the element and false means outside the element

Bool isdragging reflects whether the mouse is pressed at this time. true indicates that the mouse is pressed at this time, and false indicates that the mouse is not pressed at this time

Primitive primitive structure with color and position members

Solution

Question one

For the first question, we can find that the mouse has the following three states

  1. Mouse release

  2. Press the mouse and the mouse is outside the element

  3. Press the mouse and the mouse is inside the element

What we need to do is to distinguish these three states. We can use an int variable p to represent these three states with 0, 1 and 2 respectively. The key is how to convert these three states

0 → 1: when the mouse is pressed (isdragging), the mouse is in the element (isContained), and the mouse is released at the moment (p == 0)

0 → 2: when the mouse is pressed (isdragging), the mouse is not in the element (! isContained), and the mouse is released at the last moment (p == 0)

1 → 0, 2 → 0: when the mouse is released (! Isdragging)

This part of the code is as follows:

//Using the static variable allows p to initialize only once in a loop
static int p = 0;
if (isDraging)
{
    if (isContained)
    {
        if (p == 0) p = 1;
    }
    else
    {
        if (p == 0) p = 2;
    }
}
else
{
    p = 0;
}

Question two

For the second problem, we need to find the displacement during the movement of the mouse. We cannot directly assign the NDC coordinate of the mouse to the coordinate of the element (this will cause the element to jump to the mouse position immediately when the mouse is pressed in the element), Instead, the displacement vector coordinates from the coordinates of the moment when the mouse starts dragging to the coordinates of the mouse at this time plus the coordinates of the previous time of the element in the figure above should be assigned to the coordinates of the element at this time

The details are as follows:

As shown in the following figure, the mouse moves from B to D, and the element moves from A to C

p when the status is 0 → 1, record the mouse coordinate B, entity position A and calculate A B → \overrightarrow{AB} AB

When p is in state 1, it means that the element is being dragged. The mouse coordinate is D and the element coordinate is C. at this time, the element coordinate is updated, that is C spot sit mark = D spot sit mark − A B → Point C coordinate = point D coordinate - \ overrightarrow{AB} Coordinate of point C = coordinate of point D − AB

The code is implemented as follows

Note: the csugl namespace is created by yourself. You can refer to the logic implementation. After understanding the solution to the problem, you can write it yourself

void MouseDragger(const glm::ivec2 &winSize, csugl::Ref<Primitive> primitive)
{
    // Mouse inside element
    static bool isContained = false;
    // The mouse is being pressed
    static bool isDraging = false;
    // Is the drag process started
    static bool flag = false;
    // Mouse displacement difference
    static glm::vec2 changeCurNDCpos = {0.0f, 0.0f};

    // 1. Obtain mouse window coordinates:
    // 2. Convert to NDC coordinates: (use WindowPosToNDCPos to convert)
    // 3. Whether dragging:
    // 4. Whether it is in the element: (use primitive's is_contained detection)
    // 5. Set element color:
    // 6. Set the new coordinates of the element:

    float xPos, yPos;
    xPos = csugl::Input::GetMousePosX();
    yPos = csugl::Input::GetMousePosY();
    glm::vec2 curpos = {xPos, yPos};
    glm::vec2 curNDCpos = WindowPosToNDCPos(curpos, winSize);

    isDraging = csugl::Input::IsMouseButtonPressed(csugl::Mouse::Button0);
    isContained = primitive->is_contained(curNDCpos);

    //The variable p is used to determine whether to click the mouse in the element. 0 indicates that the mouse is released, 1 indicates that the mouse is pressed and inside the element, and 2 indicates that the mouse is pressed and outside the element
    static int p = 0;
    if (isDraging) {
        if (isContained) {
            if (p == 0) {
                changeCurNDCpos = curNDCpos - primitive->position;
                p = 1;
            }
        } else {
            if (p == 0) {
                p = 2;
            }
        }
    } else {
        p = 0;
    }
    if(p==1) {
        primitive->color = {0.1f, 0.5f, 0.8f};
        primitive->position = curNDCpos - changeCurNDCpos;
    } else {
        primitive->color = {0.8f, 0.5f, 0.1f};
    }
}

// Convert window coordinates to standard device coordinates (NDC)
glm::vec2 WindowPosToNDCPos(const glm::vec2 &winPosition, const glm::vec2 &winSize)
{
    glm::vec2 tmpPos = winPosition / winSize * 2.0f - 1.0f; //Convert to float solution
    tmpPos.y = -tmpPos.y;//The coordinates are opposite up and down
    return tmpPos;
}

Keywords: Computer Graphics

Added by volant on Tue, 26 Oct 2021 14:02:15 +0300