DrawTrace.hpp 15.2 KB
Newer Older
1 2 3 4 5 6 7
/*!
 *\file DrawTrace.hpp
 */

#ifndef DRAW_TRACE_HPP
#define DRAW_TRACE_HPP

8 9
#include <string>

10 11
#include "resource.hpp"

12
#include "../interface/render_area.hpp"
13
#include "../message/message_ns.hpp"
14

15
using namespace message_ns;
16 17 18 19 20 21 22 23 24 25 26

/*!
 * \brief 
 */
template<class T>
class DrawTrace 
{

protected:

    //  Interface_graphic* _window;
27
    std::stack<const Container *> _leaf_containers;
28 29
    std::stack<const Container *> _node_containers;
    std::map<const Container *, Element_pos, std::less<const Container *> > _container_positions;
30 31
   
    /*!
32 33 34
     * \brief The default height for containers.
     */
    static const float _DRAWING_CONTAINER_HEIGHT_DEFAULT = 1.2f;
35
     
36 37 38 39
    /*!
     * \brief The default width for containers.
     */
    static const float _DRAWING_CONTAINER_WIDTH_DEFAULT = 2.5f;
40

41 42 43 44
    /*!
     * \brief The default horizontal space between containers.
     */
    static const float _DRAWING_CONTAINER_H_SPACE_DEFAULT = 0.1f;
45

46 47 48 49
    /*!
     * \brief The default vertical space between containers.
     */
    static const float _DRAWING_CONTAINER_V_SPACE_DEFAULT = 0.2f;
50 51 52


    /*!
53 54 55
     * \brief The default height for states.
     */
    static const float _DRAWING_STATE_HEIGHT_DEFAULT = 1.2f;
56
 
57 58 59 60
    /*!
     * \brief The default vertical space between states.
     */
    static const float _DRAWING_STATE_V_SPACE_DEFAULT = 0.2f;
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85


    /*!
     * \brief Geometrical informations about the trace shape.
     */
    Element_pos _container_width;
    Element_pos _container_height;
    Element_pos _container_h_space;
    Element_pos _container_v_space;
    
    Element_pos _state_height;
    Element_pos _state_v_space;
 

public:

    /***********************************
     *
     * Constructor and destructor.
     *
     **********************************/

    /*!
     * \brief The default constructor
     */
86
    DrawTrace() {
87 88

        //   _window = NULL;
Olivier Lagrasse's avatar
Olivier Lagrasse committed
89 90 91 92
        _container_width = _DRAWING_CONTAINER_WIDTH_DEFAULT;
        _container_height = _DRAWING_CONTAINER_HEIGHT_DEFAULT;
        _container_h_space = _DRAWING_CONTAINER_H_SPACE_DEFAULT;
        _container_v_space = _DRAWING_CONTAINER_V_SPACE_DEFAULT;
93
        
Olivier Lagrasse's avatar
Olivier Lagrasse committed
94 95
        _state_height = _DRAWING_STATE_HEIGHT_DEFAULT;
        _state_v_space = _DRAWING_STATE_V_SPACE_DEFAULT;
96 97 98 99 100 101 102

    }


    /*!
     * \brief The destructor
     */
103 104
    virtual ~DrawTrace() {
    
105 106 107 108 109 110 111 112 113 114 115 116 117 118
    }



    /***********************************
      *
      * Building functions.
      *
      **********************************/


    /*!
     * \brief The trace building function.
     * \param draw_object the kind of object which will be drawn (OpenGL, SVG...).
119
     * \param trace the trace data.
120
     */
121
    void build(T* draw_object, Trace* trace) {
122 123 124 125

        draw_object->start_draw();

        draw_object->start_draw_containers();
126
        browse_container_tree(draw_object, trace);
127 128 129
        draw_object->end_draw_containers();

        draw_object->start_draw_states();
130
        browse_entities(draw_object);
131 132 133 134 135 136 137 138 139 140 141 142
        draw_object->end_draw_states();

        draw_object->end_draw();
    }


    /***********************************
     *
     * Browsing functions.
     *
     **********************************/
    
143
    inline void browse_container_tree(T* draw_object, Trace* trace){
144 145 146 147 148 149 150 151 152
         
        /*** Drawing containers ***/
        
        /*
         * Start with the root containers.
         * if a container has more than one child, it will be draw
         * vertically, else horizontally. 
         */
         
Olivier Lagrasse's avatar
Olivier Lagrasse committed
153 154
        std::stack<Element_count> position_stack;
        std::stack<Element_pos> height_stack;
155 156 157 158 159
        Element_pos x;
        Element_pos y;
        Element_pos y_buf;/* buffer for the y position */
        Element_pos height_buf;/* buffer for the container height */
        const Container* container;
160
        const std::list<Container *> *trace_container = trace->get_root_containers();
161
         
Olivier Lagrasse's avatar
Olivier Lagrasse committed
162
        std::list<Container *>::iterator it;
163 164 165 166 167 168 169 170 171 172
         
        bool isAnotherContainer = true;/* use to stop the loop */

 

        position_stack.push(0);
        height_stack.push(0);

        container = get_container(trace_container, 0);

173
        if(container == NULL) {
174 175
	  //            std::cerr << "The trace can not be shown because there are no containers." << std::endl;
	  message << "Error a container does not exist. Cannot display the trace" << ende;
176 177
            return;
        }
178 179 180 181 182 183 184 185 186 187 188 189
        if (number_of_children(container) <= 1)
            x = _container_width;
        else
            x = _container_height;
        y = 0;
        y_buf = 0;
        height_buf = 0;


        /***********************************
         * Start loop.
         **********************************/
Clément Vuchener's avatar
Clément Vuchener committed
190
        while (isAnotherContainer == true) {
191 192 193 194 195
            Element_pos buf_pos;

            buf_pos = return_last_visited_child(position_stack);

            /* If all children are not yet visited */
Clément Vuchener's avatar
Clément Vuchener committed
196
            if (buf_pos < number_of_children(container)) {
197 198 199 200 201 202 203 204 205
                /***********************************
                 * Browse children.
                 **********************************/
                position_stack.top() ++;/* add a child */
                position_stack.push(0);/* prepare for the next child */
                
                container = get_container(container->get_children(), buf_pos);
                 
                x += _container_width+_container_h_space;/* if there is just one child, container can be draw horizontally */ 
Clément Vuchener's avatar
Clément Vuchener committed
206 207
            }
            else { /* all children have been visited or there is not child, thus it's time to draw ! */
208 209
                position_stack.pop();/* remove the information of the container hence it will be drawn */
                     
Clément Vuchener's avatar
Clément Vuchener committed
210
                if (1 >= number_of_children(container)) { /* Should be drawn horizontally */
211 212 213 214 215
                    /***********************************
                     * Draw container with one or less child.
                     **********************************/
                    height_buf = 0;

Clément Vuchener's avatar
Clément Vuchener committed
216
                    if (0 == number_of_children(container)) {
217
                        /* y contains the current height, y_buf the new adding height */
Clément Vuchener's avatar
Clément Vuchener committed
218 219
                        int n = container->get_variable_number();
                        y_buf = (1+n)*(_container_height+_container_v_space);
220 221 222
                        height_stack.push(y_buf);
                        y += y_buf;

223 224
                        /* Then, we store the container */
                        _leaf_containers.push(container);
225 226
                        // and its position
                        _container_positions[container] = y;
227 228

                        height_buf =  _container_height;
Clément Vuchener's avatar
Clément Vuchener committed
229 230 231

                    }
                    else
232 233 234
                        height_buf =  height_stack.top()-_container_v_space;/* take the child's height */


235
                    draw_object->draw_container(x-_container_width, y- height_buf, _container_width, height_buf);
236 237 238 239 240
                    /* draw the container text */  
                    draw_object->draw_container_text(x- _container_width+_container_h_space, y-height_buf/2, container->get_name().to_string());

                    x -= (_container_width + _container_h_space);
                }
Clément Vuchener's avatar
Clément Vuchener committed
241
                else { /* Should be drawn vertically */
242 243 244 245 246 247 248
                    
                    /***********************************
                     * Draw container with more than one child.
                     **********************************/

                    height_buf = 0;
                    
Clément Vuchener's avatar
Clément Vuchener committed
249
                    for (int i = 0 ; i < number_of_children(container) ; i ++) {
250 251 252 253 254 255 256
                        height_buf += height_stack.top();
                        height_stack.pop();
                    }
                    
                    height_stack.push(height_buf);/* push the sum of child heights */
                    height_buf -= _container_v_space;

257
                    draw_object->draw_container(x-_container_width, y- height_buf, _container_width, height_buf);/* Vertically, it is drawn as higher as it has children */
258 259 260 261
                    /* draw the container text */                 
                    draw_object->draw_container_text(x-_container_width+_container_h_space, y- height_buf/2, container->get_name().to_string());  

                    x -= (_container_width + _container_h_space);
262 263 264
                    
                    /* Then, we store the container */
                    _node_containers.push(container);
265 266 267 268

                }
                        
                /* Now, container was drawn. It's time to go back up */
Clément Vuchener's avatar
Clément Vuchener committed
269
                if (container->get_parent() != NULL) {
270 271 272 273 274 275 276
                    /***********************************
                     * Browse parents.
                     **********************************/

                    int buf = position_stack.top();
                    position_stack.pop();
                     
Clément Vuchener's avatar
Clément Vuchener committed
277
                    if (container->get_parent()->get_parent() != NULL) {
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
                        container = get_container( container->get_parent()->get_parent()->get_children(), position_stack.top()-1);/*  '-1' because we continu with the same container, not the following */
                    }
                    else
                        container =  container->get_parent();
                    
                    position_stack.push(buf);
                     
                }
                else/* It is the root container */
                    isAnotherContainer = false;/* end of the loop */
                 
            }/* end "else" of "if (position_stack < trace_container->getChildren().size())" */
             
        }/* end "while (isAnotherContainer==true)"*/
   
    }/* end browse_container_tree */


Clément Vuchener's avatar
Clément Vuchener committed
296 297 298
    /*!
     * \brief Browse the states list and draw them
     */
299 300 301
    inline void browse_entities(T* draw_object) {
        const Container *container;
        const list<State *> *state_list;
302
        State *state;
303
        const list<Event *> *event_list;
304 305 306
        Event *event;
        const list<Link *> *link_list;
        Link *link;
Clément Vuchener's avatar
Clément Vuchener committed
307 308
        const map<VariableType *, list<pair<Date, Double> > *> *variable_map;
        list<pair<Date, Double> > *variable_values;
309 310
        const map<std::string, Value *> *extra_fields;
        const Color *color;
311 312
        Element_count i;/* for the level (y axis) of the states */
        
313 314 315 316 317 318 319 320
        i = 0;
        while (!_leaf_containers.empty()){
            container = _leaf_containers.top();
	        
	        // Browse states
	        state_list = container->get_states();
            for (list<State *>::const_iterator it = state_list->begin();
                it != state_list->end();
321
                it++) {
322
	               
323
                state = *it;
324
                Element_pos base = ((Element_pos)i)*_container_height+((Element_pos)i)*_container_v_space+_container_v_space;
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
                
                // Search the color
                extra_fields = state->get_value()->get_extra_fields();
                map<std::string, Value *>::const_iterator field = extra_fields->find(std::string("Color"));
                if (field == extra_fields->end()) {
                    /* Call the object state drawing function with default color */ 
                    draw_object->draw_state(state->get_start_time().get_value(), state->get_end_time().get_value(), base, _state_height, 0.7, 0.7, 0.75); 
                }
                else {
                    /* Call the object state drawing function with the state color */ 
                    color = (const Color *)(*field).second;
                    draw_object->draw_state(state->get_start_time().get_value(), state->get_end_time().get_value(),
                        base, _state_height,
                        color->get_red(), color->get_green(), color->get_blue());            
                }
340
            }/* end for */
341 342 343 344 345 346 347 348 349 350 351 352 353
            
            // Browse events
	        event_list = container->get_events();
            for (list<Event *>::const_iterator it = event_list->begin();
                it != event_list->end();
                it++) {
	               
                event = *it;
                Element_pos base = ((Element_pos)i)*_container_height+((Element_pos)i)*_container_v_space+_container_v_space;
                /* Call the object state drawing function */ 
                draw_object->draw_event(event->get_time().get_value(), base, _state_height); 
            }/* end for */
            
Clément Vuchener's avatar
Clément Vuchener committed
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
            // Browse events
	        variable_map = container->get_variables();
            for (map<VariableType *, list<pair<Date, Double> > *>::const_iterator it = variable_map->begin();
                it != variable_map->end();
                it++) {
	            
	            i++; // Variable are on another line
                variable_values = (*it).second;
                
                draw_object->start_draw_counter();
                for (list<pair<Date, Double> >::const_iterator value = variable_values->begin();
                    value != variable_values->end();
                    value++) {
                    Element_pos base = ((Element_pos)i)*(_container_height+_container_v_space)+_container_v_space+(*value).second.get_value();
                    /* Call the object state drawing function */ 
                    draw_object->draw_counter((*value).first.get_value(), base); 
                }
                draw_object->end_draw_counter();
            }/* end for */
            
            
375 376
            /* next container */
            _leaf_containers.pop();
377 378 379
            i++;

        }/* end while (!_stack_states.empty()) */
380 381 382 383 384 385 386 387 388 389 390
        
        while (!_node_containers.empty()){
            container = _node_containers.top();
	        
	        // Browse links
	        link_list = container->get_links();
            for (list<Link *>::const_iterator it = link_list->begin();
                it != link_list->end();
                it++) {
	               
                link = *it;
391 392
                Element_pos start = _container_positions[link->get_source()] - _container_height/2;
                Element_pos end = _container_positions[link->get_destination()] - _container_height/2;
393 394 395 396 397 398 399
                draw_object->draw_arrow(link->get_start_time().get_value(), link->get_end_time().get_value(), start, end); 
            }/* end for */
            
            /* next container */
            _node_containers.pop();

        }/* end while (!_stack_states.empty()) */
400

Clément Vuchener's avatar
Clément Vuchener committed
401
    }
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422




    /***********************************
     *
     * Browsing tools.
     *
     **********************************/

    inline Element_count number_of_children(const Container* c){
        
        if (c->get_children()==NULL){
            // _window->warning(string("Container child list is empty"));
            return 0;
        }
     
        return c->get_children()->size();
    }
 

Olivier Lagrasse's avatar
Olivier Lagrasse committed
423
    inline Element_count return_last_visited_child(std::stack<Element_count> const &s){
424 425 426 427 428 429 430 431
        if (s.empty()==true){
            //   _window->error("The render area position stack is empty.");
            return -1;
        }
        else
            return s.top();
    }
    
432
    
Olivier Lagrasse's avatar
Olivier Lagrasse committed
433 434
    inline Container* get_container(const std::list<Container*>* list_container, const int pos) const{
        std::list<Container *>::const_reverse_iterator it;
435 436
        int i=0;
        
437 438 439
        if(list_container->empty()){
            return NULL;
        }
440
        
441
        for (it=list_container->rbegin() ; i<pos; it++, i++ ){ }
442 443
        return *it;
    }
444
    
445 446 447 448

};

#endif