aboutsummaryrefslogblamecommitdiffstats
path: root/ui.cpp
blob: 52070c1106e2dc71e9b0f8f43c2ca39566ba45d3 (plain) (tree)
1
2
3
4
5
6
7
8

                   





                                          




                                                         
                                   
                                            
                                    

  


                                                   





                                                  

                         

                        
                        




                                        
                                                                                   
                                          
                                   









                                                                











                                                                    


                                                          



                                                           
                                 
                         



                                                                                           

                 




                                                      

                                         





                                             




                                                                                             

                                                                      



                               




























                                                     
                                                    



































































                                                                                                 

                                                                                    
                                 










                                                                                           










                                                                                                            
                                                                                                       





                                                                                                           





                                                                                

                                                         


                                  




                                                              

                                                                                                             

                 
                                                               
 
                                                 




                                                             
                                                






                                                     














                                                                           
         
                                                  


                            










                                                                      

 
                      



                                                                         









                                                 


                                                                      
                        

                                             




                                                             
                                                                       
 
                                                                                                                                                            


                                                    

                                                                                        



























                                                                                                                                                        
                                        

                                                                                                              


                                          








                                                                                                 
                                                       



                                   

#include <iostream>

#include "ui.hpp"

/*
    All modes :
        - h, j, k, l : move around
        - i, o : zoom in/out
    Main mode (command mode) :
        - s : select start pos
        - e : select end pos
        - a : add obstacle
        - d : delete obstacle under mouse pointer
        - g : start solving
        - f : follow trajectory mode
    Select modes : no other keys
*/

using namespace std;

UI::UI(hilare_a_param *p) : _sel_obs(vec(0,0), 0) {
    _param = p;

    _p.begin_pos.param = _p.end_pos.param = p;

    _view.x0 = _view.y0 = 0;
    _view.zoom = 1;

    _mode = M_NORMAL;

    _got_sol = true;
    _follow = false;
}

void UI::run() {
    _settings.antialiasingLevel = 8;

    _win.create(sf::VideoMode(1000, 700), "PR", sf::Style::Default, _settings);
    _win.setVerticalSyncEnabled(true);
    _win.setFramerateLimit(60);

    while (_win.isOpen()) {
        sf::Event ev;
        while (_win.pollEvent(ev)) {
            if (ev.type == sf::Event::Closed)
                _win.close();

            if (ev.type == sf::Event::TextEntered) {
                int k = ev.text.unicode;

                if (k == 'h') {
                    _view.x0 -= 20 / _view.zoom;
                } else if (k == 'j') {
                    _view.y0 += 20 / _view.zoom;
                } else if (k == 'k') {
                    _view.y0 -= 20 / _view.zoom;
                } else if (k == 'l') {
                    _view.x0 += 20 / _view.zoom;
                } else if (k == 'i') {
                    _view.zoom *= 1.1;
                } else if (k == 'o') {
                    _view.zoom /= 1.1;
                } else if (k == 'g') {
                    _solver.start(_p);
                    _got_sol = false;
                } else if (k == 'f') {
                    _follow = !_follow;
                    _follow_s = 0;
                    _follow_d = 0;
                }
            }

            if (_mode == M_NORMAL) handle_normal(ev);
            if (_mode == M_INS_OBSTACLE) handle_ins_obs(ev);
            if (_mode == M_SEL_BEGIN || _mode == M_SEL_END) handle_sel_pos(ev);
        }

        if (!_got_sol && _solver.finished()) {
            _s = _solver.get_solution();
            _got_sol = true;
        }

        if (_follow) do_follow();

        _win.clear(sf::Color::Black);

        render_internal();
        render_solution();
        render_problem();

        if (_mode == M_INS_OBSTACLE)
            render_circle(_sel_obs, sf::Color::Transparent, sf::Color::White, 0);
        if (_mode == M_SEL_BEGIN || _mode == M_SEL_END)
            render_pos(_sel_pos, sf::Color::White);

        if (_follow) render_pos(_follow_pos, sf::Color::Cyan);

        _win.display();
    }
}

void UI::handle_normal(const sf::Event &ev) {
    if (ev.type == sf::Event::TextEntered) {
        int k = ev.text.unicode;

        if (k == 's') {
            _mode = M_SEL_BEGIN;
            _sel_step = S_XY;
            _sel_pos = _p.begin_pos;
            vec p = mouse_coord();
            _sel_pos.x = p.x;
            _sel_pos.y = p.y;
        }
        if (k == 'e') {
            _mode = M_SEL_END;
            _sel_step = S_XY;
            _sel_pos = _p.end_pos;
            vec p = mouse_coord();
            _sel_pos.x = p.x;
            _sel_pos.y = p.y;
        }
        if (k == 'a') {
            _mode = M_INS_OBSTACLE;
            _sel_step = S_XY;
            _sel_obs.c = mouse_coord();
            _sel_obs.r = 20 / _view.zoom;
        }
        if (k == 'd') {
            vec p = mouse_coord();
            vector<obstacle> o2;
            for(auto& i: _p.obstacles) {
                if (!i.c.intersects(p)) o2.push_back(i);
            }
            _p.obstacles = o2;
        }
    }
}

void UI::handle_ins_obs(const sf::Event &ev) {
    if (_sel_step == S_XY) {
        if (ev.type == sf::Event::MouseMoved) {
            _sel_obs.c = mouse_coord();
        } else if (ev.type == sf::Event::MouseButtonReleased
                && ev.mouseButton.button == sf::Mouse::Button::Left) {
            _sel_step = S_RADIUS;
        }
    } else {
        if (ev.type == sf::Event::MouseMoved) {
            _sel_obs.r = (mouse_coord() - _sel_obs.c).norm();
        } else if (ev.type == sf::Event::MouseButtonReleased
                && ev.mouseButton.button == sf::Mouse::Button::Left) {
            _p.obstacles.push_back(obstacle(_sel_obs));
            _mode = M_NORMAL;
        }
    }

    if (ev.type == sf::Event::MouseButtonReleased
            && ev.mouseButton.button == sf::Mouse::Button::Right) {
        _mode = M_NORMAL;   // cancel out
    }
}

void UI::handle_sel_pos(const sf::Event &ev) {
    if (_sel_step == S_XY) {
        if (ev.type == sf::Event::MouseMoved) {
            vec p = mouse_coord();
            _sel_pos.x = p.x;
            _sel_pos.y = p.y;
        } else if (ev.type == sf::Event::MouseButtonReleased
                && ev.mouseButton.button == sf::Mouse::Button::Left) {
            _sel_step = S_THETA;
        }
    } else if (_sel_step == S_THETA) {
        if (ev.type == sf::Event::MouseMoved) {
            _sel_pos.theta = (mouse_coord() - _sel_pos.pos()).angle();
        } else if (ev.type == sf::Event::MouseButtonReleased
                && ev.mouseButton.button == sf::Mouse::Button::Left) {
            _sel_step = S_PHI;
        }
    } else {
        if (ev.type == sf::Event::MouseMoved) {
            _sel_pos.phi = (mouse_coord() - _sel_pos.pos()).angle() - _sel_pos.theta;
        } else if (ev.type == sf::Event::MouseButtonReleased
                && ev.mouseButton.button == sf::Mouse::Button::Left) {
            if (_mode == M_SEL_BEGIN) {
                _p.begin_pos = _sel_pos;
            } else {
                _p.end_pos = _sel_pos;
            }
            _mode = M_NORMAL;   // cancel out
        }
    }

    if (ev.type == sf::Event::MouseButtonReleased
            && ev.mouseButton.button == sf::Mouse::Button::Right) {
        _mode = M_NORMAL;   // cancel out
    }
}

void UI::render_circle(const circle &c, sf::Color border, sf::Color inside, int w) {
    double r = c.r * _view.zoom;
    sf::CircleShape a(r, 50);
    a.setPosition(to_view(c.c));
    a.move(-r, -r);
    a.setFillColor(inside);
    a.setOutlineColor(border);
    a.setOutlineThickness(w);
    _win.draw(a);
}

void UI::render_pos(const hilare_a &pos, sf::Color c) {
    render_circle(circle(pos.pos(), pos.param->r_c_car), c, sf::Color::Transparent, 2);

    sf::ConvexShape l;

    l.setPointCount(3);
    l.setPoint(0, to_view(pos.pos() - vec::from_polar(pos.param->r_c_car * 0.8, pos.theta + M_PI / 2)));
    l.setPoint(1, to_view(pos.pos() + vec::from_polar(pos.param->r_c_car * 0.8, pos.theta + M_PI / 2)));
    l.setPoint(2, to_view(pos.pos() + vec::from_polar(pos.param->r_c_car * 0.8, pos.theta)));

    l.setFillColor(c);

    _win.draw(l);

    render_circle(circle(pos.pos_trolley(), pos.param->r_c_trolley), c, sf::Color::Transparent, 2);

    if (fabs(pos.phi) > 0.01) {
        vec cc = pos.canon_curve_center();
        //render_circle(circle(cc, (pos.pos() - cc).norm()), c, sf::Color::Transparent, 2);
        //render_circle(circle(cc, (pos.pos_trolley() - cc).norm()), c, sf::Color::Transparent, 2);
    }
}

void UI::render_obstacle(const obstacle &o) {
    render_circle(o.c, sf::Color::Transparent, sf::Color(100, 100, 100), 0);
}

void UI::render_mvt(const hilare_a_mvt &m, sf::Color c) {
    if (m.is_arc) {
        const int nd = 42;

        sf::Vertex l[nd];

        l[0] = sf::Vertex(to_view(m.from.pos()), c);

        double th = (m.from.pos() - m.center).angle();
        double r = (m.from.pos() - m.center).norm();
        for (int i = 1; i < nd - 1; i++) {
            l[i] = sf::Vertex(to_view(m.center + vec::from_polar(r, th + m.domega * i / nd)), c);
        }

        l[nd - 1] = sf::Vertex(to_view(m.to.pos()), c);

        _win.draw(l, nd, sf::LinesStrip);
    } else {
        sf::Vertex l[] = {
            sf::Vertex(to_view(m.from.pos()), c),
            sf::Vertex(to_view(m.to.pos()), c),
        };
        _win.draw(l, 2, sf::LinesStrip);
    }
}

void UI::render_sol(const solution &s, sf::Color c) {
    for (auto i: s.movement) {
        render_mvt(i, c);
    }
}

void UI::render_problem() {
    render_pos(_p.begin_pos, sf::Color::Blue);
    render_pos(_p.end_pos, sf::Color::Red);

    for (auto i = _p.obstacles.begin(); i != _p.obstacles.end(); i++) {
        render_obstacle(*i);
    }
}

void UI::render_solution() {
    for (auto i = _s.movement.begin(); i != _s.movement.end(); i++) {
        if (i != _s.movement.begin())
            render_pos(i->from, sf::Color::Green);
    }
    render_sol(_s.movement, sf::Color::Green);
}

void UI::render_internal() {
    solver_internal x = _solver.peek_internal();

    for (auto& p: x.pts) {
        render_pos(p, sf::Color(42, 42, 42));
    }

    for (auto& kv: x.paths) {
        for (auto kv2: kv.second) {
            render_sol(kv2.second, sf::Color(42, 42, 42));
        }
    }
}

void UI::do_follow() {
    if (_s.movement.size() == 0 || _follow_s >= _s.movement.size()) {
        _follow = false;
        return;
    }

    hilare_a_mvt &m = _s.movement[_follow_s];

    int k = m.length() * _view.zoom / 2;
    const int divide = (k >= 40 ? k : 40);

    int s = _follow_d;

    if (m.dtheta_before != 0) {
        _follow_pos = m.from;
        if (s < 30) {
            _follow_pos.theta += m.dtheta_before * s / 30;
            _follow_pos.phi -= m.dtheta_before * s / 30;
        } else {
            s -= 30;
            int dd = divide - 30;

            _follow_pos.theta += m.dtheta_before;
            _follow_pos.phi -= m.dtheta_before;

            if (m.is_arc) {
                _follow_pos.theta += m.domega * s / dd;

                vec p = m.center + vec::from_polar((m.from.pos() - m.center).norm(), (m.from.pos() - m.center).angle() + m.domega * s / dd);
                _follow_pos.x = p.x;
                _follow_pos.y = p.y;
            } else {
                _follow_pos.x = (s * m.to.x + (dd - s) * m.from.x) / dd;
                _follow_pos.y = (s * m.to.y + (dd - s) * m.from.y) / dd;
            }
        }
    } else {
        _follow_pos = m.from;

        if (m.is_arc) {
            _follow_pos.theta += m.domega * s / divide;

            vec p = m.center + vec::from_polar((m.from.pos() - m.center).norm(), (m.from.pos() - m.center).angle() + m.domega * s / divide);
            _follow_pos.x = p.x;
            _follow_pos.y = p.y;
        } else {
            _follow_pos.x = (s * m.to.x + (divide - s) * m.from.x) / divide;
            _follow_pos.y = (s * m.to.y + (divide - s) * m.from.y) / divide;
        }
    }

    _view.x0 = _follow_pos.x;
    _view.y0 = _follow_pos.y;

    _follow_d++;
    if (_follow_d == divide) {
        _follow_s++;
        _follow_d = 0;
        if (_follow_s == _s.movement.size()) _follow = false;
    }
}

sf::Vector2f UI::to_view(const vec &p) {
    sf::Vector2u s = _win.getSize();
    return sf::Vector2f((p.x - _view.x0) * _view.zoom + (s.x/2), (p.y - _view.y0) * _view.zoom + (s.y/2));
}

vec UI::from_view(const sf::Vector2f &p) {
    sf::Vector2u s = _win.getSize();
    return vec((p.x - s.x/2) / _view.zoom + _view.x0, (p.y - s.y/2) / _view.zoom + _view.y0);
}

vec UI::from_view(const sf::Vector2i &p) {
    return from_view(sf::Vector2f(p.x, p.y));
}

vec UI::mouse_coord() {
    return from_view(sf::Mouse::getPosition(_win));
}

/* vim: set ts=4 sw=4 tw=0 noet :*/