• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

qt rysowanie krzywej beziera - problem ze zrozumieniem przesuwania pikseli

Object Storage Arubacloud
0 głosów
498 wizyt
pytanie zadane 2 kwietnia 2019 w C i C++ przez robertos18 Obywatel (1,120 p.)

Otóz na zajeciach z programowania przerabialismy kod z rysowania krzywej beziera niestety mnie na tych zajeciach nie było i staram się nadrobic zaleglosci niestety sam nie potrafie sobie poradzic a przegladajac internet nie potrafie znalezc satysfakcjonujacych mnie odpowiedzi. Głownie chodzi mi o dwie funkcje mianowicie: 

void MyWindow::mousePressEvent(QMouseEvent *event)
void MyWindow::mouseMoveEvent(QMouseEvent *event)

Czy ktos byłby wstanie mi troche zrozumiec kod? 

#include "mywindow.h"
#include "ui_mywindow.h"
#include <qmath.h>

MyWindow::MyWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MyWindow)
{
    ui->setupUi(this);

    szer = ui->rysujFrame->width();
    wys = ui->rysujFrame->height();
    poczX = ui->rysujFrame->x();
    poczY = ui->rysujFrame->y();

    img = new QImage(szer,wys,QImage::Format_RGB32);

    punktprzesun = -1;
}

MyWindow::~MyWindow()
{
    delete ui;
}

void MyWindow::on_exitButton_clicked()
{
    qApp->quit();
}

void MyWindow::paintEvent(QPaintEvent*)
{
    QPainter p(this);

    p.drawImage(poczX,poczY,*img);

    for(int i=0; i<wektor.size(); i++){
        p.drawImage(wektor[i].x(),wektor[i].y(),QImage(15,15,QImage::Format_RGB32));
    }
}

void MyWindow::on_cleanButton_clicked()
{
    czysc();
    update();
    wektor.resize(0);
    licz_klikniecia = 0;
}

void MyWindow::czysc()
{
    unsigned char *ptr;

    ptr = img->bits();

    int i,j;

    for(i=0; i<wys; i++)
    {
        for(j=0; j<szer; j++)
        {
            ptr[szer*4*i + 4*j]=255;
            ptr[szer*4*i + 4*j + 1] = 255;
            ptr[szer*4*i + 4*j + 2] = 255;
        }
    }
}

void MyWindow::zapalPiksel(int x, int y)
{
    unsigned char *ptr;
    ptr = img->bits();

    if ((x>=0)&&(y>=0)&&(x<szer)&&(y<wys))
    {
        ptr[szer*4*y + 4*x] = 0;
        ptr[szer*4*y + 4*x + 1] = 0;
        ptr[szer*4*y + 4*x + 2] = 0;
    }

    update();
}

void MyWindow::rysujBeziera(QPoint p0, QPoint p1, QPoint p2, QPoint p3){
    QPoint punkt;

    for(double t = 0.0; t<=1.0; t+=0.001){
        punkt = pow((1-t),3) * p0 + 3 * pow((1-t),2) * t * p1 + 3 * (1-t) * pow(t,2) * p2 + pow(t,3) * p3;
        zapalPiksel(punkt.x(), punkt.y());
    }
}

void MyWindow::mousePressEvent(QMouseEvent *event)
{
    x0 = event->x();
    y0 = event->y();
    x0 -= poczX;
    y0 -= poczY;

    if(event->buttons() == Qt::RightButton){
        QPoint punkt;

        punkt.setX(x0);
        punkt.setY(y0);

        wektor.push_back(punkt);
        licz_klikniecia++;


        if(licz_klikniecia==4){
            rysujBeziera(wektor[0],wektor[1],wektor[2], wektor[3]);
        }
        if(licz_klikniecia > 4 && ((licz_klikniecia-1)%3)==0){
            rysujBeziera(wektor[licz_klikniecia-4],wektor[licz_klikniecia-3],wektor[licz_klikniecia-2], wektor[licz_klikniecia-1]);
        }
    }
    else if(event->buttons() == Qt::LeftButton){
        for(int i=0; i<wektor.size(); i++){
            if(abs(x0 - wektor[i].x()) < 15 && abs(y0 - wektor[i].y()) < 15){
                punktprzesun = i;
            }
        }
    }

    qDebug() << wektor;
    update();
}

void MyWindow::mouseMoveEvent(QMouseEvent *event)
{
    x0 = event->x();
    y0 = event->y();
    x0 -= poczX;
    y0 -= poczY;
    czysc();
    if(punktprzesun != -1){
        wektor[punktprzesun] = QPoint(x0, y0);
    }
    if(wektor.size()>=4){
        for(int i=3; i<wektor.size(); i+=3){
            rysujBeziera(wektor[i-3],wektor[i-2],wektor[i-1], wektor[i]);
        }
    }
    update();
}

void MyWindow::mouseReleaseEvent(QMouseEvent *event)
{
    punktprzesun = -1;
}


void MyWindow::rysujOdcinek(int x0, int y0, int x1, int y1){
    float a, b;

    a = (float)(y1 - y0)/(x1 -x0);
    b = (float)(y0 - a * x0);
    if(x0 == x1)
    {
        if(y0>y1){
            int temp;
            temp = y0;
            y0 = y1;
            y1 = temp;

        }

        for(int i = y0; i <= y1; i++){
            zapalPiksel(x0,i);
        }
    }

    else if(x0 < x1)
    {
        if(abs(a) < 1)
        {
            for(int x = x0; x <=x1; x++)
            {
                int y = a * x + b;
                zapalPiksel(x,y);
            }
        }
        else if(abs(a) >= 1 && y0 < y1 )
        {
            for(int y = y0; y <=y1; y++)
            {
                int x = (y - b)/a;
                zapalPiksel(x,y);
            }
        }
        else
        {
            for(int y = y1; y <=y0; y++)
            {
                int x = (y - b)/a;
                zapalPiksel(x,y);
            }
        }
    }
    else
    {
        if(abs(a) < 1)
        {
            for(int x = x1; x <=x0; x++)
            {
                int y = a * x + b;
                zapalPiksel(x,y);
            }
        }
        else if(abs(a) >= 1 && y1 < y0)
        {
            for(int y = y1; y <=y0; y++)
            {
                int x = (y - b)/a;
                zapalPiksel(x,y);
            }
        }
        else
        {
            for(int y = y0; y <=y1; y++)
            {
                int x = (y - b)/a;
                zapalPiksel(x,y);
            }
        }
    }
}

 

1 odpowiedź

+1 głos
odpowiedź 3 kwietnia 2019 przez Bondrusiek Maniak (61,410 p.)

Witam,

jeśli nie rozumiesz zawartości kodu to polecam go debugować. W Qt Creator możesz wybrać tryb uruchomienia aplikacji (release oraz debug). W trybie debug możesz na czasie wykonywanie programu ustawiać pułapki w celu np. zatrzymania aplikacji i zobaczenie wartości

https://doc.qt.io/qtcreator/creator-debugging.html

Ewentualnie możesz dodać nagłówek qDebug

#include <QDebug>
...
void MyWindow::mousePressEvent(QMouseEvent *event)
{
    x0 = event->x();
    y0 = event->y();
    x0 -= poczX;
    y0 -= poczY;
 
     qDebug() << "x0 " << x0;
     qDebug() << "x1 " << x1;
     qDebug() << "y0 " << y0;
     qDebug() << "y1 " << y1;

    if(event->buttons() == Qt::RightButton){
        QPoint punkt;
 
        punkt.setX(x0);
        punkt.setY(y0);
 
        wektor.push_back(punkt);
        licz_klikniecia++;
 
 
        if(licz_klikniecia==4){
            rysujBeziera(wektor[0],wektor[1],wektor[2], wektor[3]);
        }
        if(licz_klikniecia > 4 && ((licz_klikniecia-1)%3)==0){
            rysujBeziera(wektor[licz_klikniecia-4],wektor[licz_klikniecia-3],wektor[licz_klikniecia-2], wektor[licz_klikniecia-1]);
        }
    }
    else if(event->buttons() == Qt::LeftButton){
        for(int i=0; i<wektor.size(); i++){
            if(abs(x0 - wektor[i].x()) < 15 && abs(y0 - wektor[i].y()) < 15){
                punktprzesun = i;
            }
        }
    }
 
    qDebug() << wektor;
    update();
}
...

Tym sposobem możesz przeanalizować cały kod.

komentarz 14 kwietnia 2019 przez robertos18 Obywatel (1,120 p.)

Ogolnie ideę tego kodu rozumiem, mam metodę void MyWindow::mousePressEvent(QMouseEvent *event), do której przekazuje zdarzenie kliknięcia myszą. 
w x0 i y0 sa przypisane punkty tego klikniecia
potem odejmuje wspolrzedne poczatku okna dzieki ktoremu krzywa rysuje się wyznaczonym oknie, następnie mam 

QPoint punkt;

punkt.setX( x0 );
punkt.setY( y0 );

w dokumentacji jest napisane ze Qpoint definuje punkt na plaszczyznie a

setX

Ustawia współrzędną x tego punktu na podaną współrzędną x .
natomiast 

setY

Ustawia współrzędną y tego punktu na podaną współrzędną y .
Nie potrafię zrozumiec po co zostałą utworzona ta klasa i potem setX i setY? teraz w zmiennej punkt siedza wspolrzedne klikniecia x0 i y0? ale po co zostala utworzona nowa zmienna skoro te wspolrzedne juz są tu
 

x0 = event->x();
y0 = event->y();

Prosiłbym o wytłumaczenie z góry dziękuję

1
komentarz 15 kwietnia 2019 przez Bondrusiek Maniak (61,410 p.)

Nie potrafię zrozumiec po co zostałą utworzona ta klasa i potem setX i setY? teraz w zmiennej punkt siedza wspolrzedne klikniecia x0 i y0? ale po co zostala utworzona nowa zmienna skoro te wspolrzedne juz są tu

Po to bo klasa QPoint posiada dodatkowe funkcje składowe zmienne, które nie posiada zwykły typ int.  Dodatkowo do wektora należy dodać typ QPoint a nie zwykłe zmienne int.

https://doc.qt.io/qt-5/qpoint.html

komentarz 15 kwietnia 2019 przez robertos18 Obywatel (1,120 p.)

Okej to to juz zrozumialem, dziękuję 
Chciałbym zrozumiec jeszcze jak działa przesuwanie a nastepnie rysowanie krzywej, probóję to swoimi słowami opisac ale tak srednio jestem pewny tego co piszę

void MyWindow::mouseMoveEvent(QMouseEvent *event)
{
    x0 = event->x();
    y0 = event->y();
    x0 -= poczX;
    y0 -= poczY;
    czysc();
    if(punktprzesun != -1){
        wektor[punktprzesun] = QPoint(x0, y0);
    }
    if(wektor.size()>=4){
        for(int i=3; i<wektor.size(); i+=3){
            rysujBeziera(wektor[i-3],wektor[i-2],wektor[i-1], wektor[i]);
        }
    }
    update();
}

wchodzę do funkcji gdzie wywoływana jest metoda przemieszczania myszy
gdy nacisnę na dany kwadracik i przesunę go (bez puszczania lewego przycisku myszy) do tablicy wektor zostaja przypisane współrzedne puszczenia myszy? 
No i gdy tych kwadracikow jest wiecej niz 4 

for(int i=3; i<wektor.size(); i+=3){
            rysujBeziera(wektor[i-3],wektor[i-2],wektor[i-1], wektor[i]);

tego nie rozumiem.. Prosiłbym o wytłumaczenie

komentarz 16 kwietnia 2019 przez Bondrusiek Maniak (61,410 p.)
for(int i=3; i<wektor.size(); i+=3)

Tutaj masz pętle, która zaczyna od 3 i jest inkrementowana co 3 a wartość i jest musi być mniejsza od zawartości wektora. Co każdą iteracje wykonywana jest funkcja

rysujBeziera(wektor[i-3],wektor[i-2],wektor[i-1], wektor[i]);

która, fest odzwierciedleniem krzywej Beziera(tu trzeba przeanalizować definicje tej funkcji, ja matematycznie do końca jej nie znam).

Co do

void MyWindow::mouseMoveEvent(QMouseEvent *event)

to potrafi ona odczytać tylko pozycję myszy tylko wtedy gdy przycisk myszy jest wciśnięty.

Podobne pytania

0 głosów
1 odpowiedź 184 wizyt
pytanie zadane 22 czerwca 2017 w C i C++ przez Bartosz Pajewski Początkujący (480 p.)
+1 głos
1 odpowiedź 283 wizyt
pytanie zadane 6 października 2019 w C i C++ przez Jakub 0 Pasjonat (23,120 p.)
0 głosów
2 odpowiedzi 298 wizyt
pytanie zadane 5 sierpnia 2019 w C i C++ przez Ewaryst Ławecki Obywatel (1,710 p.)

92,674 zapytań

141,575 odpowiedzi

320,045 komentarzy

62,038 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...