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

question-closed SFML - Rotate poprzez przeciąganie

VPS Starter Arubacloud
0 głosów
356 wizyt
pytanie zadane 11 października 2015 w C i C++ przez criss Mędrzec (172,590 p.)
zamknięte 12 października 2015 przez criss

Nie moge sobie poradzić z problemem (jak w temacie). Sprawa wygląda tak:

Mam prostokąt (RectangleShape). Origin ma ustawiony na punkt (x0, y0), połowa długości krótszej ściany - jeśli ktoś się nie orientuje, origin to punkt na obiekcie względem którego jest wykonywany obrót. Chciałbym go obracać "przeciągajac go". Póki co dąże do tego, żeby obracał się w strone miejsca w które klikne myszką. Jeśli w chwili kliknięcia jest poziomo (stan początkowy) i kąt obrotu nie będzie powyżej ~30*, to całkiem nieźle działa. Jeśli nie jest już poziomo - dzieją się różne rzeczy. Jęsli kąt jest większy niż te ~30* - zwiększa się błąd i obraca się troche za bardzo.

A więc wygląda to tak: 
Klikam myszką, obliczana jest różnica, załóżmy delta = Yp - (wsp. Y puntu kliknięcia myszką). Kąt jest obliczny z arc-tangensa, w c++ atanf(delta / R). R - jak na rysunku - szerokość prostokąta.

Wzór na punkt (Xp, Yp) policzyłem z równań prostej przechodzącej przez (x0, y0) i (Xp, Yp) oraz okręgu po którym obraca się prostokąt (środek (x0, y0) , promień R). Wyszło: Xp = R / sqrt(1 + tg^2(alfa) ) + x0 i
Yp = Xp * tg(alfa) + y0 - x0 * tg(alfa). Kat alfa to oczywiście aktualne obrócenie naszego prostokąta względem poziomu. Tego wzoru jestem niemal pewien.

W założeniu ma to wyglądać tak, że klikam myszką na prostokąt i trzymając myszke przeciagam i obracam tyle ile chce. Dodam, że raczej nie potzrebny mi maksymalny obrót większy niż 90*.
W każdym razie - nie wiem co tu nie działa, możliwe, że jest już byt skomplikowane i nie ogarniam. A może da się to rozwiązać w zupełnie inny, prostszy sposób?

Tutaj rysunek do którego przez cały czas się odnosiłem:

I kod: 

sf::Vector2f pos(sf::RectangleShape& rect){
        const float x0 = rect.getPosition().x;
        const float y0 = rect.getPosition().y;
        const float R = rect.getSize().y;
        const float arc = rect.getRotation();
        const float tg = tan(arc);

        float X = R / sqrtf(pow(tg, 2) + 1) + x0;
        float Y = X * tg + y0 - (x0 * tg);
        return sf::Vector2f(X, Y);

}

int main(){

    sf::RenderWindow window(sf::VideoMode(500, 500), "okno");
    window.setFramerateLimit(60);
    sf::RectangleShape shape(sf::Vector2f(200.f, 80.f));
    shape.setFillColor(sf::Color::Green);
    shape.setOrigin(200.f, 40.f);
    shape.setPosition(250.f, 250.f);

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed){
                window.close();
                return 0;
            }
            if ( sf::Mouse::isButtonPressed(sf::Mouse::Left)){
                    float a = pos(shape).y - sf::Mouse::getPosition(window).y;
                    std::cout<<"shape posY: "<<pos(shape).y<<std::endl;
                    std::cout<<"mouse posY: "<<sf::Mouse::getPosition(window).y<<std::endl;
                    std::cout<<"a: "<<a<<std::endl;
                    float b = shape.getSize().x;
                    std::cout<<"b: "<<b<<std::endl;
                    float arc = atanf(a/b) * 180.f / 3.14;
                    shape.rotate(arc);
                    std::cout<<arc<<std::endl;
            }

        }
        window.clear(sf::Color::White);
        window.draw(shape);
        window.display();
}
}

 

komentarz zamknięcia: wyjaśnione w odpowiedziach

2 odpowiedzi

0 głosów
odpowiedź 11 października 2015 przez criss Mędrzec (172,590 p.)

Hmm... Możliwe, że wiem gdzie jest problem. Delta ( w programie a) powinna być odległością między prostą przechodząca przez punkty (x0, y0) i (Xp, Yp) a punktem kliknięcia (długość odcinka poprowadzonego pod katem prostym ze wspomnianej prostej do pkt kliku). Nie wiem czy mam racje - jutro sprawdze, aczkolwiek jeśli znajdzie ktoś prostsze rozwiązanie / zweryfikuje moje - byłbym bardzo wdzięczny :)

0 głosów
odpowiedź 12 października 2015 przez maly Nałogowiec (37,190 p.)
edycja 12 października 2015 przez maly

Trochę przekombinowałeś.

Raczej wystarczy obliczyć kąt wektora myszy względem pozycji shape.

float getAngleDeg(const sf::Vector2f &v )
{
    return std::atan2(v.y,v.x)*(180.0f/3.141592653589);
}

sf::Vector2f mouse_pos = window.mapPixelToCoords(sf::Mouse::getPosition(window));

sf::Vector2f transformed = mouse_pos - shape.getPosition();
float angle = getAngleDeg(transformed);
shape.setRotation(angle);

 

komentarz 12 października 2015 przez criss Mędrzec (172,590 p.)
Tak, już zdąrzyłem na to wpaść.

PS: dopiero zaczynam z sfml-em i troche się męczyłem bo w Mouse::getPosition nie podałem okna jako argument :D Także jakby ktoś trafił na ten temat, to niech sie upewni, że to zrobił :P

Podobne pytania

0 głosów
2 odpowiedzi 186 wizyt
pytanie zadane 17 kwietnia 2017 w HTML i CSS przez czujek22 Dyskutant (7,670 p.)
–1 głos
3 odpowiedzi 858 wizyt
pytanie zadane 19 marca 2017 w OpenGL, Unity przez Emil Panecki Bywalec (2,100 p.)
–1 głos
1 odpowiedź 970 wizyt
pytanie zadane 8 października 2016 w JavaScript przez Protekton123 Użytkownik (700 p.)

92,454 zapytań

141,262 odpowiedzi

319,099 komentarzy

61,854 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

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

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!

...